KF2-Server-Extension/ServerExtMut/Classes/ServerExtMut.uc

1915 lines
60 KiB
Ucode
Raw Normal View History

2017-10-20 02:00:49 +00:00
// Server extension mutator, by Marco.
Class ServerExtMut extends KFMutator
config(ServerExtMut);
// Webadmin
var array<FWebAdminConfigInfo> WebConfigs;
struct FInventory
{
var class<Inventory> ItemClass;
var int Values[4];
};
struct CFGCustomZedXP
{
var string zed; // zed name
var float XP1; // normal
var float XP2; // hard
var float XP3; // suicidal
var float XP4; // hoe
};
2017-10-20 02:00:49 +00:00
struct FSavedInvEntry
{
var Controller OwnerPlayer;
var byte Gren;
var array<FInventory> Inv;
};
var array<FSavedInvEntry> PlayerInv;
var config array<string> PerkClasses,CustomChars,AdminCommands,CustomItems,BonusGameSongs,BonusGameFX;
var config array<CFGCustomZedXP> CustomZedXP;
2017-10-20 02:00:49 +00:00
var array< class<Ext_PerkBase> > LoadedPerks;
var array<FCustomCharEntry> CustomCharList;
var ExtPlayerStat ServerStatLoader;
var KFPawn LastHitZed;
var int LastHitHP;
var ExtPlayerController LastDamageDealer;
var vector LastDamagePosition;
var private const array<string> DevList;
var transient private array<UniqueNetId> DevNetID;
var ExtXMLOutput FileOutput;
var transient class<DamageType> LastKillDamageType;
var SoundCue BonusGameCue;
var Object BonusGameFXObj;
var array<FCustomTraderItem> CustomItemList;
var KFGFxObject_TraderItems CustomTrader;
const SettingsTagVer=14;
2017-10-20 02:00:49 +00:00
var KFGameReplicationInfo KF;
var config int SettingsInit;
var config int ForcedMaxPlayers,PlayerRespawnTime,LargeMonsterHP,StatAutoSaveWaves,MinUnloadPerkLevel,PostGameRespawnCost,MaxTopPlayers;
var config float UnloadPerkExpCost;
var globalconfig string ServerMOTD,StatFileDir;
var array<Controller> PendingSpawners;
var int LastWaveNum,NumWaveSwitches;
var ExtSpawnPointHelper SpawnPointer;
var bool bRespawnCheck,bSpecialSpawn,bGameHasEnded,bIsPostGame;
var config bool bKillMessages,bDamageMessages,bEnableMapVote,bNoAdminCommands,bNoWebAdmin,bNoBoomstickJumping,bDumpXMLStats,bRagdollFromFall,bRagdollFromMomentum,bRagdollFromBackhit,bAddCountryTags,bThrowAllWeaponsOnDeath;
2020-01-09 11:05:13 +00:00
var config bool bServerPerksMode;
var config bool bDontUseOriginalWeaponry;
var config bool bAllowStandartPistolUpgrade;
var config bool bDisableCustomTrader;
2017-10-20 02:00:49 +00:00
2022-05-18 05:56:26 +00:00
var KFGI_Access KFGIA;
//Custom XP lightly array
struct CustomZedXPStruct
{
var class<KFPawn_Monster> zedclass;
var float XPValues[4];
};
var array<CustomZedXPStruct> CustomZedXPArray;
2017-10-20 02:00:49 +00:00
function PostBeginPlay()
{
local xVotingHandler MV;
local int i,j;
local class<Ext_PerkBase> PK;
local UniqueNetId Id;
local KFCharacterInfo_Human CH;
local ObjectReferencer OR;
local Object O;
local string S;
local bool bLock;
Super.PostBeginPlay();
2020-11-28 20:12:58 +00:00
if (WorldInfo.Game.BaseMutator==None)
2017-10-20 02:00:49 +00:00
WorldInfo.Game.BaseMutator = Self;
else WorldInfo.Game.BaseMutator.AddMutator(Self);
2020-11-28 20:12:58 +00:00
if (bDeleteMe) // This was a duplicate instance of the mutator.
2017-10-20 02:00:49 +00:00
return;
SpawnPointer = class'ExtSpawnPointHelper'.Static.FindHelper(WorldInfo); // Start init world pathlist.
//OnlineSubsystemSteamworks(class'GameEngine'.Static.GetOnlineSubsystem()).Int64ToUniqueNetId("",Id);
//`Log("TEST"@class'OnlineSubsystem'.Static.UniqueNetIdToString(Id));
DevNetID.Length = DevList.Length;
2020-11-28 20:12:58 +00:00
for (i=0; i<DevList.Length; ++i)
2017-10-20 02:00:49 +00:00
{
class'OnlineSubsystem'.Static.StringToUniqueNetId(DevList[i],Id);
DevNetID[i] = Id;
}
2022-05-18 05:56:26 +00:00
2017-10-20 02:00:49 +00:00
ServerStatLoader = new (None) class'ExtPlayerStat';
WorldInfo.Game.HUDType = class'KFExtendedHUD';
WorldInfo.Game.PlayerControllerClass = class'ExtPlayerController';
WorldInfo.Game.PlayerReplicationInfoClass = class'ExtPlayerReplicationInfo';
WorldInfo.Game.DefaultPawnClass = class'ExtHumanPawn';
KFGameInfo(WorldInfo.Game).CustomizationPawnClass = class'ExtPawn_Customization';
KFGameInfo(WorldInfo.Game).KFGFxManagerClass = class'ExtMoviePlayer_Manager';
2022-05-18 05:56:26 +00:00
KFGIA = new(KFGameInfo(WorldInfo.Game)) class'KFGI_Access';
2017-10-20 02:00:49 +00:00
// trader things
2020-11-28 20:12:58 +00:00
if (!bDisableCustomTrader && CustomTrader==None)
{
CustomTrader = class'ExtPlayerReplicationInfo'.Static.CreateNewList();
SetTimer(0.001, false, 'EditTraiderItems');
}
2020-11-28 20:12:58 +00:00
if (ServerMOTD=="")
2017-10-20 02:00:49 +00:00
ServerMOTD = "Message of the Day";
2020-11-28 20:12:58 +00:00
if (StatFileDir=="")
2017-10-20 02:00:49 +00:00
{
StatFileDir = "../../KFGame/Script/%s.usa";
Default.StatFileDir = "../../KFGame/Script/%s.usa";
}
2020-11-28 20:12:58 +00:00
if (SettingsInit!=SettingsTagVer)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (SettingsInit==0)
2017-10-20 02:00:49 +00:00
ForcedMaxPlayers = 6;
2020-11-28 20:12:58 +00:00
if (SettingsInit<2)
2017-10-20 02:00:49 +00:00
{
bKillMessages = true;
bDamageMessages = true;
LargeMonsterHP = 800;
}
2020-11-28 20:12:58 +00:00
if (SettingsInit<3)
2017-10-20 02:00:49 +00:00
bEnableMapVote = true;
2020-11-28 20:12:58 +00:00
if (SettingsInit<5)
2017-10-20 02:00:49 +00:00
{
StatAutoSaveWaves = 1;
PerkClasses.Length = 10;
PerkClasses[0] = PathName(class'Ext_PerkBerserker');
PerkClasses[1] = PathName(class'Ext_PerkCommando');
PerkClasses[2] = PathName(class'Ext_PerkFieldMedic');
PerkClasses[3] = PathName(class'Ext_PerkSupport');
PerkClasses[4] = PathName(class'Ext_PerkDemolition');
PerkClasses[5] = PathName(class'Ext_PerkFirebug');
PerkClasses[6] = PathName(class'Ext_PerkGunslinger');
PerkClasses[7] = PathName(class'Ext_PerkSharpshooter');
PerkClasses[8] = PathName(class'Ext_PerkSWAT');
PerkClasses[9] = PathName(class'Ext_PerkSurvivalist');
}
2020-11-28 20:12:58 +00:00
else if (SettingsInit<11)
2017-10-20 02:00:49 +00:00
{
PerkClasses.AddItem(PathName(class'Ext_PerkSharpshooter'));
PerkClasses.AddItem(PathName(class'Ext_PerkSWAT'));
PerkClasses.AddItem(PathName(class'Ext_PerkSurvivalist'));
}
2020-11-28 20:12:58 +00:00
else if (SettingsInit==11)
2017-10-20 02:00:49 +00:00
PerkClasses.AddItem(PathName(class'Ext_PerkSurvivalist'));
2020-11-28 20:12:58 +00:00
if (SettingsInit<6)
2017-10-20 02:00:49 +00:00
{
MinUnloadPerkLevel = 25;
UnloadPerkExpCost = 0.1;
}
2020-11-28 20:12:58 +00:00
if (SettingsInit<8)
2017-10-20 02:00:49 +00:00
{
AdminCommands.Length = 2;
AdminCommands[0] = "Kick:Kick Player";
AdminCommands[1] = "KickBan:Kick-Ban Player";
}
2020-11-28 20:12:58 +00:00
if (SettingsInit<9)
2017-10-20 02:00:49 +00:00
MaxTopPlayers = 50;
2020-11-28 20:12:58 +00:00
if (SettingsInit < 13)
{
bAllowStandartPistolUpgrade = True;
bDisableCustomTrader = False;
}
if (SettingsInit < 14)
{
bThrowAllWeaponsOnDeath = False;
}
2017-10-20 02:00:49 +00:00
SettingsInit = SettingsTagVer;
SaveConfig();
}
2020-11-28 20:12:58 +00:00
for (i=0; i<PerkClasses.Length; ++i)
2017-10-20 02:00:49 +00:00
{
PK = class<Ext_PerkBase>(DynamicLoadObject(PerkClasses[i],class'Class'));
2020-11-28 20:12:58 +00:00
if (PK!=None)
2017-10-20 02:00:49 +00:00
{
LoadedPerks.AddItem(PK);
PK.Static.CheckConfig();
}
}
j = 0;
2020-11-28 20:12:58 +00:00
for (i=0; i<CustomChars.Length; ++i)
2017-10-20 02:00:49 +00:00
{
bLock = Left(CustomChars[i],1)=="*";
S = (bLock ? Mid(CustomChars[i],1) : CustomChars[i]);
CH = KFCharacterInfo_Human(DynamicLoadObject(S,class'KFCharacterInfo_Human',true));
2020-11-28 20:12:58 +00:00
if (CH!=None)
2017-10-20 02:00:49 +00:00
{
CustomCharList.Length = j+1;
CustomCharList[j].bLock = bLock;
CustomCharList[j].Char = CH;
++j;
continue;
}
OR = ObjectReferencer(DynamicLoadObject(S,class'ObjectReferencer'));
2020-11-28 20:12:58 +00:00
if (OR!=None)
2017-10-20 02:00:49 +00:00
{
foreach OR.ReferencedObjects(O)
{
2020-11-28 20:12:58 +00:00
if (KFCharacterInfo_Human(O)!=None)
2017-10-20 02:00:49 +00:00
{
CustomCharList.Length = j+1;
CustomCharList[j].bLock = bLock;
CustomCharList[j].Char = KFCharacterInfo_Human(O);
CustomCharList[j].Ref = OR;
++j;
}
}
}
}
// Bonus (pong) game contents.
2020-11-28 20:12:58 +00:00
if (BonusGameSongs.Length>0)
2017-10-20 02:00:49 +00:00
{
BonusGameCue = SoundCue(DynamicLoadObject(BonusGameSongs[Rand(BonusGameSongs.Length)],class'SoundCue'));
}
2020-11-28 20:12:58 +00:00
if (BonusGameFX.Length>0)
2017-10-20 02:00:49 +00:00
{
BonusGameFXObj = DynamicLoadObject(BonusGameFX[Rand(BonusGameFX.Length)],class'Object');
2020-11-28 20:12:58 +00:00
if (SoundCue(BonusGameFXObj)==None && ObjectReferencer(BonusGameFXObj)==None) // Check valid type.
2017-10-20 02:00:49 +00:00
BonusGameFXObj = None;
}
2020-11-28 20:12:58 +00:00
if (ForcedMaxPlayers>0)
2017-10-20 02:00:49 +00:00
{
SetMaxPlayers();
SetTimer(0.001,false,'SetMaxPlayers');
}
bRespawnCheck = (PlayerRespawnTime>0);
2020-11-28 20:12:58 +00:00
if (bRespawnCheck)
2017-10-20 02:00:49 +00:00
SetTimer(1,true);
2020-11-28 20:12:58 +00:00
if (bEnableMapVote)
2017-10-20 02:00:49 +00:00
{
foreach DynamicActors(class'xVotingHandler',MV)
break;
2020-11-28 20:12:58 +00:00
if (MV==None)
2017-10-20 02:00:49 +00:00
MV = Spawn(class'xVotingHandler');
MV.BaseMutator = Class;
}
SetTimer(1,true,'CheckWave');
2020-11-28 20:12:58 +00:00
if (!bNoWebAdmin && WorldInfo.NetMode!=NM_StandAlone)
2017-10-20 02:00:49 +00:00
SetTimer(0.1,false,'SetupWebAdmin');
2020-11-28 20:12:58 +00:00
if (bDumpXMLStats)
2017-10-20 02:00:49 +00:00
FileOutput = Spawn(class'ExtXMLOutput');
UpdateCustomZedXPArray();
// Causes bugs
// SetTimer(0.1,'CheckPickupFactories')
}
function UpdateCustomZedXPArray()
{
local int i;
local CustomZedXPStruct zedxp;
CustomZedXPArray.Length = 0;
// Custom XP for custom zeds
2020-11-28 20:12:58 +00:00
for (i=0;i<CustomZedXP.Length;i++)
{
zedxp.zedclass = class<KFPawn_Monster>(DynamicLoadObject(CustomZedXP[i].zed,Class'Class'));
2020-11-28 20:12:58 +00:00
if (zedxp.zedclass == none)
{
`log("Error loading"@CustomZedXP[i].zed);
continue;
}
zedxp.XPValues[0] = CustomZedXP[i].XP1;
zedxp.XPValues[1] = CustomZedXP[i].XP2;
zedxp.XPValues[2] = CustomZedXP[i].XP3;
zedxp.XPValues[3] = CustomZedXP[i].XP4;
CustomZedXPArray.AddItem(zedxp);
`log("CustomXP: Loaded"@PathName(zedxp.zedclass));
}
}
// function CheckPickupFactories()
// {
// local KFPickupFactory_Item ItemFactory;
// // Disable 9mm and medpistol in all PickupFactories
// foreach AllActors(class'KFPickupFactory_Item', ItemFactory)
// {
2020-11-28 20:12:58 +00:00
// for (i=0;i<ItemFactory.ItemPickups.Length;i++)
// {
2020-11-28 20:12:58 +00:00
// if (ItemFactory.ItemPickups[i].ItemClass == class'KFGameContent.KFWeap_Pistol_9mm'
// || ItemFactory.ItemPickups[i].ItemClass == class'KFGameContent.KFWeap_Pistol_Medic')
// {
// ItemFactory.ItemPickups.Remove(i, 1);
// break;
// }
// }
// }
// }
function EditTraiderItems()
{
local int i;
local KFGFxObject_TraderItems Trad;
2020-11-28 20:12:58 +00:00
if (!bDontUseOriginalWeaponry)
{
Trad = KFGameReplicationInfo(WorldInfo.GRI).TraderItems;
// Remove dual 9mm, 9mm, medpistol
2020-11-28 20:12:58 +00:00
for (i=0;i<Trad.SaleItems.Length;i++)
{
2020-11-28 20:12:58 +00:00
if (string(Trad.SaleItems[i].ClassName) ~= "KFWeap_Pistol_Dual9mm"
|| string(Trad.SaleItems[i].ClassName) ~= "KFWeap_Pistol_Medic"
|| string(Trad.SaleItems[i].ClassName) ~= "KFWeap_Pistol_9mm")
{
// Remove pistols
continue;
}
// Adding original weapon
AddCIToTraderEx(Trad.SaleItems[i].WeaponDef);
}
}
// Reinfo and resorting items
// MyKFGI.MyKFGRI.TraderItems.SetItemsInfo(MyKFGI.MyKFGRI.TraderItems.SaleItems);
// MyKFGI.MyKFGRI.TraderItems.SortItemsInfo(MyKFGI.MyKFGRI.TraderItems.SaleItems);
2020-11-28 20:12:58 +00:00
if (bAllowStandartPistolUpgrade)
{
// Add custom 9mm for upgrades
AddCIToTrader("ServerExt.ExtWeapDef_9mm");
// Add custom medpistol for upgrades
AddCIToTrader("ServerExt.ExtWeapDef_MedicPistol");
}
// Add custom items from WebAdmin
2020-11-28 20:12:58 +00:00
for (i=0; i<CustomItems.Length; ++i)
{
AddCIToTrader(CustomItems[i]);
}
InitGRIList();
}
function AddCIToTrader(string weapdef)
{
local FCustomTraderItem CI;
CI.WeaponDef = class<KFWeaponDefinition>(DynamicLoadObject(weapdef,class'Class'));
2020-11-28 20:12:58 +00:00
if (CI.WeaponDef == None)
return;
CI.WeaponClass = class<KFWeapon>(DynamicLoadObject(CI.WeaponDef.Default.WeaponClassPath,class'Class'));
2020-11-28 20:12:58 +00:00
if (CI.WeaponClass == None)
return;
CustomItemList.AddItem(CI);
class'ExtPlayerReplicationInfo'.Static.SetWeaponInfo(WorldInfo.NetMode==NM_DedicatedServer,CustomTrader.SaleItems.Length,CI,CustomTrader);
}
function AddCIToTraderEx(class<KFWeaponDefinition> weapdef)
{
local FCustomTraderItem CI;
CI.WeaponDef = weapdef;
2020-11-28 20:12:58 +00:00
if (CI.WeaponDef == None)
return;
CI.WeaponClass = class<KFWeapon>(DynamicLoadObject(CI.WeaponDef.Default.WeaponClassPath,class'Class'));
2020-11-28 20:12:58 +00:00
if (CI.WeaponClass == None)
return;
CustomItemList.AddItem(CI);
class'ExtPlayerReplicationInfo'.Static.SetWeaponInfo(WorldInfo.NetMode==NM_DedicatedServer,CustomTrader.SaleItems.Length,CI,CustomTrader);
2017-10-20 02:00:49 +00:00
}
2020-11-28 20:04:55 +00:00
static final function string GetStatFile(const out UniqueNetId UID)
2017-10-20 02:00:49 +00:00
{
return Repl(Default.StatFileDir,"%s","U_"$class'OnlineSubsystem'.Static.UniqueNetIdToString(UID));
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function bool IsDev(const out UniqueNetId UID)
2017-10-20 02:00:49 +00:00
{
local int i;
2020-11-28 20:12:58 +00:00
for (i=(DevNetID.Length-1); i>=0; --i)
if (DevNetID[i]==UID)
2017-10-20 02:00:49 +00:00
return true;
return false;
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function InitGRIList()
{
local ExtPlayerController PC;
KFGameReplicationInfo(WorldInfo.GRI).TraderItems = CustomTrader;
// Must sync up local client.
2020-11-28 20:12:58 +00:00
if (WorldInfo.NetMode==NM_StandAlone)
2017-10-20 02:00:49 +00:00
{
foreach LocalPlayerControllers(class'ExtPlayerController',PC)
2020-11-28 20:12:58 +00:00
if (PC.PurchaseHelper!=None)
2017-10-20 02:00:49 +00:00
PC.PurchaseHelper.TraderItems = CustomTrader;
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function CheckWave()
{
2020-11-28 20:12:58 +00:00
if (KF==None)
2017-10-20 02:00:49 +00:00
{
KF = KFGameReplicationInfo(WorldInfo.GRI);
2020-11-28 20:12:58 +00:00
if (KF==None)
2017-10-20 02:00:49 +00:00
return;
}
2020-11-28 20:12:58 +00:00
if (LastWaveNum!=KF.WaveNum)
2017-10-20 02:00:49 +00:00
{
LastWaveNum = KF.WaveNum;
NotifyWaveChange();
}
2020-11-28 20:12:58 +00:00
if (!bGameHasEnded && KF.bMatchIsOver) // HACK, since KFGameInfo_Survival doesn't properly notify mutators of this!
2017-10-20 02:00:49 +00:00
{
SaveAllPerks(true);
bGameHasEnded = true;
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function NotifyWaveChange()
{
local ExtPlayerController ExtPC;
2020-07-07 19:59:38 +00:00
local KFProj_RicochetStickBullet KFBolt;
2020-11-28 20:12:58 +00:00
if (bRespawnCheck)
2017-10-20 02:00:49 +00:00
{
bIsPostGame = (KF.WaveMax<KF.WaveNum);
bRespawnCheck = (!bIsPostGame || PostGameRespawnCost>=0);
2020-11-28 20:12:58 +00:00
if (bRespawnCheck)
2017-10-20 02:00:49 +00:00
SavePlayerInventory();
}
2020-11-28 20:12:58 +00:00
if (StatAutoSaveWaves>0 && ++NumWaveSwitches>=StatAutoSaveWaves)
2017-10-20 02:00:49 +00:00
{
NumWaveSwitches = 0;
SaveAllPerks();
}
2020-11-28 20:12:58 +00:00
if (!KF.bTraderIsOpen)
{
foreach WorldInfo.AllControllers(class'ExtPlayerController',ExtPC)
ExtPC.bSetPerk = false;
}
2020-07-07 19:59:38 +00:00
foreach WorldInfo.AllActors(class'KFProj_RicochetStickBullet', KFBolt)
{
2020-11-28 20:12:58 +00:00
if (KFProj_Bolt_CompoundBowSharp(KFBolt) != none ||
2020-07-07 19:59:38 +00:00
KFProj_Bolt_Crossbow(KFBolt) != none)
KFBolt.Destroy();
}
2017-10-20 02:00:49 +00:00
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function SetupWebAdmin()
{
local WebServer W;
local WebAdmin A;
local ExtWebApp xW;
local byte i;
foreach AllActors(class'WebServer',W)
break;
2020-11-28 20:12:58 +00:00
if (W!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for (i=0; (i<10 && A==None); ++i)
2017-10-20 02:00:49 +00:00
A = WebAdmin(W.ApplicationObjects[i]);
2020-11-28 20:12:58 +00:00
if (A!=None)
2017-10-20 02:00:49 +00:00
{
xW = new (None) class'ExtWebApp';
xW.MyMutator = Self;
A.addQueryHandler(xW);
}
else `Log("ExtWebAdmin ERROR: No valid WebAdmin application found!");
}
else `Log("ExtWebAdmin ERROR: No WebServer object found!");
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function SetMaxPlayers()
{
local OnlineGameSettings GameSettings;
WorldInfo.Game.MaxPlayers = ForcedMaxPlayers;
WorldInfo.Game.MaxPlayersAllowed = ForcedMaxPlayers;
2020-11-28 20:12:58 +00:00
if (WorldInfo.Game.GameInterface!=None)
2017-10-20 02:00:49 +00:00
{
GameSettings = WorldInfo.Game.GameInterface.GetGameSettings(WorldInfo.Game.PlayerReplicationInfoClass.default.SessionName);
2020-11-28 20:12:58 +00:00
if (GameSettings!=None)
2017-10-20 02:00:49 +00:00
GameSettings.NumPublicConnections = ForcedMaxPlayers;
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function AddMutator(Mutator M)
{
2020-11-28 20:12:58 +00:00
if (M!=Self) // Make sure we don't get added twice.
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (M.Class==Class)
2017-10-20 02:00:49 +00:00
M.Destroy();
else Super.AddMutator(M);
}
}
function bool IsFromMod(Object O)
{
2020-11-28 19:53:57 +00:00
local string PackageName;
2020-11-28 20:12:58 +00:00
if (O == None)
2020-11-28 19:53:57 +00:00
return false;
PackageName = string(O.GetPackageName());
2020-11-28 20:12:58 +00:00
if (Len(PackageName)>1 && InStr(Caps(PackageName), "KF") == 0)
2020-11-28 19:53:57 +00:00
{
PackageName = string(O);
2020-11-28 20:12:58 +00:00
if (Len(PackageName)>1 && InStr(Caps(PackageName), "KF") == 0)
2020-11-28 19:53:57 +00:00
return false;
}
return true;
}
function bool HasModsInDamageInfo(DamageInfo DI)
{
local class<Actor> DamageCauser;
local class<KFDamageType> DamageType;
foreach DI.DamageCausers(DamageCauser)
if (IsFromMod(DamageCauser))
return true;
foreach DI.DamageTypes(DamageType)
if (IsFromMod(DamageType))
return true;
return false;
}
2020-11-28 22:51:29 +00:00
function CustomXP(Controller Killer, Controller Killed)
2017-10-20 02:00:49 +00:00
{
2020-11-28 22:51:29 +00:00
local KFPlayerController KFPC;
local KFPawn_Monster KFM;
local int i;
2020-11-28 19:53:57 +00:00
local KFPlayerReplicationInfo DamagerKFPRI;
local float XP;
local KFPerk InstigatorPerk;
local DamageInfo DamageInfo;
local class<KFPerk> DamagePerk;
KFM = KFPawn_Monster(Killed.Pawn);
foreach KFM.DamageHistory(DamageInfo)
2017-10-20 02:00:49 +00:00
{
DamagerKFPRI = KFPlayerReplicationInfo(DamageInfo.DamagerPRI);
if (DamagerKFPRI == None) continue;
// if no mods - exit the loop, the game will add experience by itself
if (!HasModsInDamageInfo(DamageInfo) && !KFGIA.IsCustomZed(KFM.class)) continue;
KFPC = KFPlayerController(DamagerKFPRI.Owner);
if (KFPC == None) continue;
i = CustomZedXPArray.Find('zedclass', KFM.Class);
if (i != INDEX_NONE)
2020-11-28 19:53:57 +00:00
{
XP = CustomZedXPArray[i].XPValues[MyKFGI.GameDifficulty];
}
else
{
XP = KFM.static.GetXPValue(MyKFGI.GameDifficulty);
}
InstigatorPerk = KFPC.GetPerk();
// Special for survivalist - he gets experience for everything
// and for TF2Sentry - it has no perk in DamageHistory
if (InstigatorPerk.ShouldGetAllTheXP() || DamageInfo.DamagePerks.Length == 0)
{
KFPC.OnPlayerXPAdded(XP, InstigatorPerk.Class);
continue;
}
XP /= DamageInfo.DamagePerks.Length;
foreach DamageInfo.DamagePerks(DamagePerk)
{
KFPC.OnPlayerXPAdded(FCeil(XP), DamagePerk);
2020-11-28 19:53:57 +00:00
}
2017-10-20 02:00:49 +00:00
}
2020-11-28 22:51:29 +00:00
}
function ScoreKill(Controller Killer, Controller Killed)
{
local KFPlayerController KFPC;
local ExtPlayerController ExtPC;
local ExtPerkManager KillersPerk;
local KFPawn_Monster KFPM;
2020-11-28 22:51:29 +00:00
if (bRespawnCheck && Killed.bIsPlayer)
CheckRespawn(Killed);
KFPM = KFPawn_Monster(Killed.Pawn);
if (KFPM != None && Killed.GetTeamNum() != 0
&& Killer != None && Killer.bIsPlayer && Killer.GetTeamNum() == 0)
2020-11-28 22:51:29 +00:00
{
ExtPC = ExtPlayerController(Killer);
if (ExtPC != None && ExtPC.ActivePerkManager != None)
ExtPC.ActivePerkManager.PlayerKilled(KFPM, LastKillDamageType);
if (bKillMessages && Killer.PlayerReplicationInfo != None)
BroadcastKillMessage(Killed.Pawn, Killer);
2020-11-28 22:51:29 +00:00
CustomXP(Killer, Killed);
}
if (MyKFGI != None && MyKFGI.IsZedTimeActive() && KFPM != None)
{
KFPC = KFPlayerController(Killer);
if (KFPC != None)
{
KillersPerk = ExtPerkManager(KFPC.GetPerk());
if (MyKFGI.ZedTimeRemaining > 0.f && KillersPerk != None && KillersPerk.GetZedTimeExtensions(KFPC.GetLevel() ) > MyKFGI.ZedTimeExtensionsUsed)
{
MyKFGI.DramaticEvent(1.0);
MyKFGI.ZedTimeExtensionsUsed++;
}
}
}
2020-11-28 22:51:29 +00:00
ExtPC = ExtPlayerController(Killed);
if (ExtPC != None)
CheckPerkChange(ExtPC);
2017-10-20 02:00:49 +00:00
if (NextMutator != None)
NextMutator.ScoreKill(Killer, Killed);
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function bool PreventDeath(Pawn Killed, Controller Killer, class<DamageType> damageType, vector HitLocation)
{
2020-11-28 20:12:58 +00:00
if ((KFPawn_Human(Killed)!=None && CheckPreventDeath(KFPawn_Human(Killed),Killer,damageType)) || Super.PreventDeath(Killed,Killer,damageType,HitLocation))
2017-10-20 02:00:49 +00:00
return true;
LastKillDamageType = damageType;
2020-11-28 20:12:58 +00:00
if (Killed.Controller!=None && KFPawn_Monster(Killed)!=None)
2017-10-20 02:00:49 +00:00
{
// Hack for when pet kills a zed.
2020-11-28 20:12:58 +00:00
if (Killed.GetTeamNum()!=0)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (Killer!=None && Killer!=Killed.Controller && Killer.GetTeamNum()==0 && Ext_T_MonsterPRI(Killer.PlayerReplicationInfo)!=None)
2017-10-20 02:00:49 +00:00
GT_PlayerKilled(Ext_T_MonsterPRI(Killer.PlayerReplicationInfo).OwnerController,Killed.Controller,damageType);
}
// Broadcast pet's deathmessage.
2020-11-28 20:12:58 +00:00
else if (Killed.PlayerReplicationInfo!=None && PlayerController(Killed.Controller)==None && damageType!=class'KFDT_Healing')
2017-10-20 02:00:49 +00:00
BroadcastFFDeath(Killer,Killed,damageType);
}
return false;
}
// Replica of KFGameInfo.Killed base.
2020-11-28 20:04:55 +00:00
final function GT_PlayerKilled(Controller Killer, Controller Killed, class<DamageType> damageType)
2017-10-20 02:00:49 +00:00
{
local ExtPlayerController KFPC;
local KFPawn_Monster MonsterPawn;
local KFGameInfo KFG;
KFG = KFGameInfo(WorldInfo.Game);
ScoreKill(Killer,Killed); // Broadcast kill message.
KFPC = ExtPlayerController(Killer);
MonsterPawn = KFPawn_Monster(Killed.Pawn);
2020-11-28 20:12:58 +00:00
if (KFG!=None && KFPC != none && MonsterPawn!=none)
2017-10-20 02:00:49 +00:00
{
//Chris: We have to do it earlier here because we need a damage type
2020-11-28 20:04:55 +00:00
KFPC.AddZedKill(MonsterPawn.class, KFG.GameDifficulty, damageType, false);
2017-10-20 02:00:49 +00:00
// Not support in v1096: KFGameInfo.CheckForBerserkerSmallRadiusKill
2020-11-28 20:12:58 +00:00
//if (KFPC.ActivePerkManager!=none && KFPC.ActivePerkManager.CanEarnSmallRadiusKillXP(damageType))
2020-11-28 20:04:55 +00:00
// KFG.CheckForBerserkerSmallRadiusKill(MonsterPawn, KFPC);
2017-10-20 02:00:49 +00:00
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function bool CheckPreventDeath(KFPawn_Human Victim, Controller Killer, class<DamageType> damageType)
2017-10-20 02:00:49 +00:00
{
local ExtPlayerController E;
2020-11-28 20:12:58 +00:00
if (Victim.IsA('KFPawn_Customization'))
2017-10-20 02:00:49 +00:00
return false;
E = ExtPlayerController(Victim.Controller);
return (E!=None && E.ActivePerkManager!=None && E.ActivePerkManager.CurrentPerk!=None && E.ActivePerkManager.CurrentPerk.PreventDeath(Victim,Killer,damageType));
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function BroadcastKillMessage(Pawn Killed, Controller Killer)
2017-10-20 02:00:49 +00:00
{
local ExtPlayerController E;
2020-11-28 20:12:58 +00:00
if (Killer==None || Killer.PlayerReplicationInfo==None)
2017-10-20 02:00:49 +00:00
return;
2020-11-28 20:12:58 +00:00
if (Killed.Default.Health>=LargeMonsterHP)
2017-10-20 02:00:49 +00:00
{
foreach WorldInfo.AllControllers(class'ExtPlayerController',E)
2020-11-28 20:12:58 +00:00
if (!E.bClientHideKillMsg)
2017-10-20 02:00:49 +00:00
E.ReceiveKillMessage(Killed.Class,true,Killer.PlayerReplicationInfo);
}
2020-11-28 20:12:58 +00:00
else if (ExtPlayerController(Killer)!=None && !ExtPlayerController(Killer).bClientHideKillMsg)
2017-10-20 02:00:49 +00:00
ExtPlayerController(Killer).ReceiveKillMessage(Killed.Class);
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function BroadcastFFDeath(Controller Killer, Pawn Killed, class<DamageType> damageType)
2017-10-20 02:00:49 +00:00
{
local ExtPlayerController E;
local PlayerReplicationInfo KillerPRI;
local string P;
local bool bFF;
P = Killed.PlayerReplicationInfo.PlayerName;
2020-11-28 20:12:58 +00:00
if (Killer==None || Killer==Killed.Controller)
2017-10-20 02:00:49 +00:00
{
foreach WorldInfo.AllControllers(class'ExtPlayerController',E)
E.ClientZedKillMessage(damageType,P);
return;
}
bFF = (Killer.GetTeamNum()==0);
KillerPRI = Killer.PlayerReplicationInfo;
2020-11-28 20:12:58 +00:00
if (PlayerController(Killer)==None)
2017-10-20 02:00:49 +00:00
KillerPRI = None;
foreach WorldInfo.AllControllers(class'ExtPlayerController',E)
E.ClientZedKillMessage(damageType,P,KillerPRI,Killer.Pawn.Class,bFF);
}
function NetDamage(int OriginalDamage, out int Damage, Pawn Injured, Controller InstigatedBy, vector HitLocation, out vector Momentum, class<DamageType> DamageType, Actor DamageCauser)
{
if (NextMutator != None)
NextMutator.NetDamage(OriginalDamage, Damage, Injured, InstigatedBy, HitLocation, Momentum, DamageType, DamageCauser);
2020-11-28 20:12:58 +00:00
if (LastDamageDealer!=None) // Make sure no other damagers interfear with the old thing going on.
2017-10-20 02:00:49 +00:00
{
ClearTimer('CheckDamageDone');
CheckDamageDone();
}
2020-11-28 20:04:55 +00:00
if (KFPawn_Monster(Injured) != None && InstigatedBy != none && InstigatedBy.GetTeamNum() == Injured.GetTeamNum())
2017-10-21 16:12:14 +00:00
{
Momentum = vect(0,0,0);
Damage = 0;
return;
}
2020-11-28 20:12:58 +00:00
if (Damage>0 && InstigatedBy!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (KFPawn_Monster(Injured)!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (Injured.GetTeamNum()!=0)
2017-10-20 02:00:49 +00:00
{
LastDamageDealer = ExtPlayerController(InstigatedBy);
2020-11-28 20:12:58 +00:00
if (bDamageMessages && LastDamageDealer!=None && !LastDamageDealer.bNoDamageTracking)
{
// Must delay this until next to get accurate damage dealt result.
LastHitZed = KFPawn(Injured);
LastHitHP = LastHitZed.Health;
LastDamagePosition = HitLocation;
SetTimer(0.001,false,'CheckDamageDone');
}
else
{
LastDamageDealer = None;
// Give credits to pet's owner.
2020-11-28 20:12:58 +00:00
if (Ext_T_MonsterPRI(InstigatedBy.PlayerReplicationInfo)!=None)
HackSetHistory(KFPawn(Injured),Injured,Ext_T_MonsterPRI(InstigatedBy.PlayerReplicationInfo).OwnerController,Damage,HitLocation);
}
2017-10-20 02:00:49 +00:00
}
else if (InstigatedBy.Pawn != None && KFPawn(InstigatedBy.Pawn).GetTeamNum() != KFPawn(Injured).GetTeamNum())
2017-10-20 02:00:49 +00:00
{
Momentum = vect(0,0,0);
Damage = 0;
2017-10-20 02:00:49 +00:00
}
}
2020-11-28 20:12:58 +00:00
else if (bDamageMessages && KFPawn_Human(Injured)!=None && Injured.GetTeamNum()==0 && InstigatedBy.GetTeamNum()!=0 && ExtPlayerController(InstigatedBy)!=None)
2017-10-20 02:00:49 +00:00
{
LastDamageDealer = ExtPlayerController(InstigatedBy);
2020-11-28 20:12:58 +00:00
if (bDamageMessages && !LastDamageDealer.bClientHideNumbers)
2017-10-20 02:00:49 +00:00
{
// Must delay this until next to get accurate damage dealt result.
LastHitZed = KFPawn(Injured);
LastHitHP = LastHitZed.Health;
LastDamagePosition = HitLocation;
SetTimer(0.001,false,'CheckDamageDone');
}
}
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
final function CheckDamageDone()
{
local int Damage;
2020-11-28 20:12:58 +00:00
if (LastDamageDealer!=None && LastHitZed!=None && LastHitHP!=LastHitZed.Health)
2017-10-20 02:00:49 +00:00
{
Damage = LastHitHP-Max(LastHitZed.Health,0);
2020-11-28 20:12:58 +00:00
if (Damage>0)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (!LastDamageDealer.bClientHideDamageMsg && KFPawn_Monster(LastHitZed)!=None)
2017-10-20 02:00:49 +00:00
LastDamageDealer.ReceiveDamageMessage(LastHitZed.Class,Damage);
2020-11-28 20:12:58 +00:00
if (!LastDamageDealer.bClientHideNumbers)
2017-10-20 02:00:49 +00:00
LastDamageDealer.ClientNumberMsg(Damage,LastDamagePosition,DMG_PawnDamage);
}
}
LastDamageDealer = None;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function HackSetHistory(KFPawn C, Pawn Injured, Controller Player, int Damage, vector HitLocation)
2017-10-20 02:00:49 +00:00
{
local int i;
local ExtPlayerController PC;
2020-11-28 20:12:58 +00:00
if (Player==None)
2017-10-20 02:00:49 +00:00
return;
PC = ExtPlayerController(Player);
2020-11-28 20:12:58 +00:00
if (bDamageMessages && PC!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (!PC.bClientHideDamageMsg)
2017-10-20 02:00:49 +00:00
PC.ReceiveDamageMessage(Injured.Class,Damage);
2020-11-28 20:12:58 +00:00
if (!PC.bClientHideNumbers)
2017-10-20 02:00:49 +00:00
PC.ClientNumberMsg(Damage,HitLocation,DMG_PawnDamage);
}
i = C.DamageHistory.Find('DamagerController',Player);
2020-11-28 20:12:58 +00:00
if (i==-1)
2017-10-20 02:00:49 +00:00
{
i = C.DamageHistory.Length;
C.DamageHistory.Length = i+1;
C.DamageHistory[i].DamagerController = Player;
C.DamageHistory[i].DamagerPRI = Player.PlayerReplicationInfo;
C.DamageHistory[i].DamagePerks.AddItem(class'ExtPerkManager');
C.DamageHistory[i].Damage = Damage;
}
2020-11-28 20:12:58 +00:00
else if ((WorldInfo.TimeSeconds-C.DamageHistory[i].LastTimeDamaged)<10)
2017-10-20 02:00:49 +00:00
C.DamageHistory[i].Damage += Damage;
else C.DamageHistory[i].Damage = Damage;
C.DamageHistory[i].LastTimeDamaged = WorldInfo.TimeSeconds;
C.DamageHistory[i].TotalDamage += Damage;
}
function bool HandleRestartGame()
{
2020-11-28 20:12:58 +00:00
if (!bGameHasEnded)
2017-10-20 02:00:49 +00:00
{
SaveAllPerks(true);
bGameHasEnded = true;
}
return Super.HandleRestartGame();
}
function NotifyLogout(Controller Exiting)
{
2020-11-28 20:12:58 +00:00
if (KFPlayerController(Exiting)!=None)
2017-10-20 02:00:49 +00:00
RemoveRespawn(Exiting);
2020-11-28 20:12:58 +00:00
if (!bGameHasEnded && ExtPlayerController(Exiting)!=None)
2017-10-20 02:00:49 +00:00
{
CheckPerkChange(ExtPlayerController(Exiting));
SavePlayerPerk(ExtPlayerController(Exiting));
}
2020-11-28 20:04:55 +00:00
if (NextMutator != None)
2017-10-20 02:00:49 +00:00
NextMutator.NotifyLogout(Exiting);
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function NotifyLogin(Controller NewPlayer)
{
2020-11-28 20:12:58 +00:00
if (ExtPlayerController(NewPlayer)!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (ExtPlayerReplicationInfo(NewPlayer.PlayerReplicationInfo)!=None)
2017-10-20 02:00:49 +00:00
InitCustomChars(ExtPlayerReplicationInfo(NewPlayer.PlayerReplicationInfo));
2020-11-28 20:12:58 +00:00
if (bAddCountryTags && NetConnection(PlayerController(NewPlayer).Player)!=None)
2017-10-20 02:00:49 +00:00
ExtPlayerReplicationInfo(NewPlayer.PlayerReplicationInfo).SetPlayerNameTag(class'CtryDatabase'.Static.GetClientCountryStr(PlayerController(NewPlayer).GetPlayerNetworkAddress()));
ExtPlayerReplicationInfo(NewPlayer.PlayerReplicationInfo).bIsDev = IsDev(NewPlayer.PlayerReplicationInfo.UniqueId);
2020-11-28 20:12:58 +00:00
if (WorldInfo.NetMode!=NM_StandAlone)
2017-10-20 02:00:49 +00:00
ExtPlayerReplicationInfo(NewPlayer.PlayerReplicationInfo).OnRepNextItem = GetNextItem;
2020-11-28 20:12:58 +00:00
if (BonusGameCue!=None || BonusGameFXObj!=None)
2017-10-20 02:00:49 +00:00
ExtPlayerController(NewPlayer).ClientSetBonus(BonusGameCue,BonusGameFXObj);
2020-11-28 20:12:58 +00:00
if (bRespawnCheck)
2017-10-20 02:00:49 +00:00
CheckRespawn(NewPlayer);
2020-11-28 20:12:58 +00:00
if (!bGameHasEnded)
2017-10-20 02:00:49 +00:00
InitializePerks(ExtPlayerController(NewPlayer));
SendMOTD(ExtPlayerController(NewPlayer));
}
2020-11-28 20:04:55 +00:00
if (NextMutator != None)
2017-10-20 02:00:49 +00:00
NextMutator.NotifyLogin(NewPlayer);
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function InitializePerks(ExtPlayerController Other)
2017-10-20 02:00:49 +00:00
{
local ExtPerkManager PM;
local Ext_PerkBase P;
local int i;
Other.OnChangePerk = PlayerChangePerk;
Other.OnBoughtStats = PlayerBuyStats;
Other.OnBoughtTrait = PlayerBoughtTrait;
Other.OnPerkReset = ResetPlayerPerk;
Other.OnAdminHandle = AdminCommand;
Other.OnSetMOTD = AdminSetMOTD;
Other.OnRequestUnload = PlayerUnloadInfo;
Other.OnSpectateChange = PlayerChangeSpec;
Other.OnClientGetStat = class'ExtStatList'.Static.GetStat;
PM = Other.ActivePerkManager;
PM.InitPerks();
2020-11-28 20:12:58 +00:00
for (i=0; i<LoadedPerks.Length; ++i)
2017-10-20 02:00:49 +00:00
{
P = Spawn(LoadedPerks[i],Other);
PM.RegisterPerk(P);
}
ServerStatLoader.FlushData();
2020-11-28 20:12:58 +00:00
if (ServerStatLoader.LoadStatFile(Other))
2017-10-20 02:00:49 +00:00
{
ServerStatLoader.ToStart();
PM.LoadData(ServerStatLoader);
2020-11-28 20:12:58 +00:00
if (Default.MaxTopPlayers>0)
2017-10-20 02:00:49 +00:00
class'ExtStatList'.Static.SetTopPlayers(Other);
}
PM.ServerInitPerks();
PM.InitiateClientRep();
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function SendMOTD(ExtPlayerController PC)
2017-10-20 02:00:49 +00:00
{
local string S;
local int i;
S = ServerMOTD;
2020-11-28 20:12:58 +00:00
while (Len(S)>510)
2017-10-20 02:00:49 +00:00
{
PC.ReceiveServerMOTD(Left(S,500),false);
S = Mid(S,500);
}
PC.ReceiveServerMOTD(S,true);
2020-11-28 20:12:58 +00:00
for (i=0; i<AdminCommands.Length; ++i)
2017-10-20 02:00:49 +00:00
PC.AddAdminCmd(AdminCommands[i]);
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function SavePlayerPerk(ExtPlayerController PC)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (PC.ActivePerkManager!=None && PC.ActivePerkManager.bStatsDirty)
2017-10-20 02:00:49 +00:00
{
// Verify broken stats.
2020-11-28 20:12:58 +00:00
if (PC.ActivePerkManager.bUserStatsBroken)
2017-10-20 02:00:49 +00:00
{
PC.ClientMessage("Warning: Your stats are broken, not saving.",'Priority');
return;
}
ServerStatLoader.FlushData();
2020-11-28 20:12:58 +00:00
if (ServerStatLoader.LoadStatFile(PC) && ServerStatLoader.GetSaveVersion()!=PC.ActivePerkManager.UserDataVersion)
2017-10-20 02:00:49 +00:00
{
PC.ActivePerkManager.bUserStatsBroken = true;
PC.ClientMessage("Warning: Your stats save data version differs from what is loaded, stat saving disabled to prevent stats loss.",'Priority');
return;
}
// Actually save.
ServerStatLoader.FlushData();
PC.ActivePerkManager.SaveData(ServerStatLoader);
ServerStatLoader.SaveStatFile(PC);
PC.ActivePerkManager.bStatsDirty = false;
// Write XML output.
2020-11-28 20:12:58 +00:00
if (FileOutput!=None)
2017-10-20 02:00:49 +00:00
FileOutput.DumpXML(PC.ActivePerkManager);
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function SaveAllPerks(optional bool bOnEndGame)
2017-10-20 02:00:49 +00:00
{
local ExtPlayerController PC;
2020-11-28 20:12:58 +00:00
if (bGameHasEnded)
2017-10-20 02:00:49 +00:00
return;
foreach WorldInfo.AllControllers(class'ExtPlayerController',PC)
2020-11-28 20:12:58 +00:00
if (PC.ActivePerkManager!=None && PC.ActivePerkManager.bStatsDirty)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (bOnEndGame)
2017-10-20 02:00:49 +00:00
CheckPerkChange(PC);
SavePlayerPerk(PC);
}
}
2020-11-28 20:04:55 +00:00
function CheckRespawn(Controller PC)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (!PC.bIsPlayer || ExtPlayerReplicationInfo(PC.PlayerReplicationInfo)==None || PC.PlayerReplicationInfo.bOnlySpectator || WorldInfo.Game.bWaitingToStartMatch || WorldInfo.Game.bGameEnded)
2017-10-20 02:00:49 +00:00
return;
// VS redead.
2020-11-28 20:12:58 +00:00
if (ExtHumanPawn(PC.Pawn)!=None && ExtHumanPawn(PC.Pawn).bPendingRedead)
2017-10-20 02:00:49 +00:00
return;
2020-11-28 20:12:58 +00:00
if (bIsPostGame && PC.PlayerReplicationInfo.Score<PostGameRespawnCost)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (PlayerController(PC)!=None)
2017-10-20 02:00:49 +00:00
PlayerController(PC).ClientMessage("You can't afford to respawn anymore (need "$PostGameRespawnCost@Chr(163)$")!",'LowCriticalEvent');
return;
}
ExtPlayerReplicationInfo(PC.PlayerReplicationInfo).RespawnCounter = PlayerRespawnTime;
PC.PlayerReplicationInfo.bForceNetUpdate = true;
2020-11-28 20:12:58 +00:00
if (PendingSpawners.Find(PC)<0)
2017-10-20 02:00:49 +00:00
PendingSpawners.AddItem(PC);
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function RemoveRespawn(Controller PC)
2017-10-20 02:00:49 +00:00
{
ExtPlayerReplicationInfo(PC.PlayerReplicationInfo).RespawnCounter = -1;
PendingSpawners.RemoveItem(PC);
}
2020-11-28 20:04:55 +00:00
final function InitPlayer(ExtHumanPawn Other)
2017-10-20 02:00:49 +00:00
{
local ExtPlayerReplicationInfo PRI;
PRI = ExtPlayerReplicationInfo(Other.PlayerReplicationInfo);
2020-11-28 20:12:58 +00:00
if (PRI!=None && PRI.PerkManager!=None && PRI.PerkManager.CurrentPerk!=None)
2017-10-20 02:00:49 +00:00
PRI.PerkManager.CurrentPerk.ApplyEffectsTo(Other);
Other.bRagdollFromFalling = bRagdollFromFall;
Other.bRagdollFromMomentum = bRagdollFromMomentum;
Other.bRagdollFromBackhit = bRagdollFromBackhit;
Other.bThrowAllWeaponsOnDeath = bThrowAllWeaponsOnDeath;
2017-10-20 02:00:49 +00:00
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function ModifyPlayer(Pawn Other)
{
2020-11-28 20:12:58 +00:00
if (ExtHumanPawn(Other)!=None)
2017-10-20 02:00:49 +00:00
InitPlayer(ExtHumanPawn(Other));
2020-11-28 20:04:55 +00:00
if (NextMutator != None)
2017-10-20 02:00:49 +00:00
NextMutator.ModifyPlayer(Other);
}
function Timer()
{
local int i;
local Controller PC;
local bool bSpawned,bAllDead;
bAllDead = (KFGameInfo(WorldInfo.Game).GetLivingPlayerCount()<=0 || WorldInfo.Game.bGameEnded || !bRespawnCheck);
2020-11-28 20:12:58 +00:00
for (i=0; i<PendingSpawners.Length; ++i)
2017-10-20 02:00:49 +00:00
{
PC = PendingSpawners[i];
2020-11-28 20:12:58 +00:00
if (bAllDead || PC==None || PC.PlayerReplicationInfo.bOnlySpectator || (PC.Pawn!=None && PC.Pawn.IsAliveAndWell()))
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (PC!=None)
2017-10-20 02:00:49 +00:00
{
ExtPlayerReplicationInfo(PC.PlayerReplicationInfo).RespawnCounter = -1;
PC.PlayerReplicationInfo.bForceNetUpdate = true;
}
PendingSpawners.Remove(i--,1);
}
2020-11-28 20:12:58 +00:00
else if (bIsPostGame && PC.PlayerReplicationInfo.Score<PostGameRespawnCost)
2017-10-20 02:00:49 +00:00
{
ExtPlayerReplicationInfo(PC.PlayerReplicationInfo).RespawnCounter = -1;
PC.PlayerReplicationInfo.bForceNetUpdate = true;
2020-11-28 20:12:58 +00:00
if (PlayerController(PC)!=None)
2017-10-20 02:00:49 +00:00
PlayerController(PC).ClientMessage("You can't afford to respawn anymore (need "$PostGameRespawnCost@Chr(163)$")!",'LowCriticalEvent');
PendingSpawners.Remove(i--,1);
}
2020-11-28 20:12:58 +00:00
else if (--ExtPlayerReplicationInfo(PC.PlayerReplicationInfo).RespawnCounter<=0)
2017-10-20 02:00:49 +00:00
{
PC.PlayerReplicationInfo.bForceNetUpdate = true;
ExtPlayerReplicationInfo(PC.PlayerReplicationInfo).RespawnCounter = 0;
2020-11-28 20:12:58 +00:00
if (!bSpawned) // Spawn only one player at time (so game doesn't crash if many players spawn in same time).
2017-10-20 02:00:49 +00:00
{
bSpawned = true;
2020-11-28 20:12:58 +00:00
if (RespawnPlayer(PC))
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (bIsPostGame)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (PlayerController(PC)!=None)
2017-10-20 02:00:49 +00:00
PlayerController(PC).ClientMessage("This respawn cost you "$PostGameRespawnCost@Chr(163)$"!",'LowCriticalEvent');
PC.PlayerReplicationInfo.Score-=PostGameRespawnCost;
}
ExtPlayerReplicationInfo(PC.PlayerReplicationInfo).RespawnCounter = -1;
PC.PlayerReplicationInfo.bForceNetUpdate = true;
}
}
}
else PC.PlayerReplicationInfo.bForceNetUpdate = true;
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
final function SavePlayerInventory()
{
local KFPawn_Human P;
local int i,j;
local Inventory Inv;
local KFWeapon K;
PlayerInv.Length = 0;
i = 0;
foreach WorldInfo.AllPawns(class'KFPawn_Human',P)
2020-11-28 20:12:58 +00:00
if (P.IsAliveAndWell() && P.InvManager!=None && P.Controller!=None && P.Controller.PlayerReplicationInfo!=None)
2017-10-20 02:00:49 +00:00
{
PlayerInv.Length = i+1;
PlayerInv[i].OwnerPlayer = P.Controller;
PlayerInv[i].Gren = KFInventoryManager(P.InvManager).GrenadeCount;
j = 0;
foreach P.InvManager.InventoryActors(class'Inventory',Inv)
{
2020-11-28 20:12:58 +00:00
if (KFInventory_Money(Inv)!=None)
2017-10-20 02:00:49 +00:00
continue;
K = KFWeapon(Inv);
2020-11-28 20:12:58 +00:00
if (K!=None && !K.bCanThrow) // Skip non-throwable items.
2017-10-20 02:00:49 +00:00
continue;
PlayerInv[i].Inv.Length = j+1;
PlayerInv[i].Inv[j].ItemClass = Inv.Class;
2020-11-28 20:12:58 +00:00
if (K!=None)
2017-10-20 02:00:49 +00:00
{
PlayerInv[i].Inv[j].Values[0] = K.SpareAmmoCount[0];
PlayerInv[i].Inv[j].Values[1] = K.SpareAmmoCount[1];
PlayerInv[i].Inv[j].Values[2] = K.AmmoCount[0];
PlayerInv[i].Inv[j].Values[3] = K.AmmoCount[1];
}
++j;
}
++i;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function bool AddPlayerSpecificInv(Pawn Other)
2017-10-20 02:00:49 +00:00
{
local int i,j;
local Inventory Inv;
local KFWeapon K;
2020-11-28 20:12:58 +00:00
for (i=(PlayerInv.Length-1); i>=0; --i)
if (PlayerInv[i].OwnerPlayer==Other.Controller)
2017-10-20 02:00:49 +00:00
{
KFInventoryManager(Other.InvManager).bInfiniteWeight = true;
KFInventoryManager(Other.InvManager).GrenadeCount = PlayerInv[i].Gren;
2020-11-28 20:12:58 +00:00
for (j=(PlayerInv[i].Inv.Length-1); j>=0; --j)
2017-10-20 02:00:49 +00:00
{
Inv = Other.InvManager.FindInventoryType(PlayerInv[i].Inv[j].ItemClass,false);
2020-11-28 20:12:58 +00:00
if (Inv==None)
2017-10-20 02:00:49 +00:00
{
Inv = Other.InvManager.CreateInventory(PlayerInv[i].Inv[j].ItemClass);
}
K = KFWeapon(Inv);
2020-11-28 20:12:58 +00:00
if (K!=None)
2017-10-20 02:00:49 +00:00
{
K.SpareAmmoCount[0] = PlayerInv[i].Inv[j].Values[0];
K.SpareAmmoCount[1] = PlayerInv[i].Inv[j].Values[1];
K.AmmoCount[0] = PlayerInv[i].Inv[j].Values[2];
K.AmmoCount[1] = PlayerInv[i].Inv[j].Values[3];
K.ClientForceAmmoUpdate(K.AmmoCount[0],K.SpareAmmoCount[0]);
K.ClientForceSecondaryAmmoUpdate(K.AmmoCount[1]);
}
}
2020-11-28 20:12:58 +00:00
if (Other.InvManager.FindInventoryType(class'KFInventory_Money',true)==None)
2017-10-20 02:00:49 +00:00
Other.InvManager.CreateInventory(class'KFInventory_Money');
KFInventoryManager(Other.InvManager).bInfiniteWeight = false;
return true;
}
return false;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:12:58 +00:00
final function Pawn SpawnDefaultPawnfor (Controller NewPlayer, Actor StartSpot) // Clone of GameInfo one, but with Actor StartSpot.
2017-10-20 02:00:49 +00:00
{
local class<Pawn> PlayerClass;
local Rotator R;
local Pawn ResultPawn;
PlayerClass = WorldInfo.Game.GetDefaultPlayerClass(NewPlayer);
R.Yaw = StartSpot.Rotation.Yaw;
ResultPawn = Spawn(PlayerClass,,,StartSpot.Location,R,,true);
return ResultPawn;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function bool RespawnPlayer(Controller NewPlayer)
2017-10-20 02:00:49 +00:00
{
local KFPlayerReplicationInfo KFPRI;
local KFPlayerController KFPC;
local Actor startSpot;
local int Idx;
local array<SequenceObject> Events;
local SeqEvent_PlayerSpawned SpawnedEvent;
local LocalPlayer LP;
2020-11-28 20:12:58 +00:00
if (NewPlayer.Pawn!=None)
2017-10-20 02:00:49 +00:00
NewPlayer.Pawn.Destroy();
// figure out the team number and find the start spot
StartSpot = SpawnPointer.PickBestSpawn();
// if a start spot wasn't found,
if (startSpot == None)
{
// check for a previously assigned spot
if (NewPlayer.StartSpot != None)
{
StartSpot = NewPlayer.StartSpot;
`warn("Player start not found, using last start spot");
}
else
{
// otherwise abort
`warn("Player start not found, failed to restart player");
return false;
}
}
// try to create a pawn to use of the default class for this player
2020-11-28 20:12:58 +00:00
NewPlayer.Pawn = SpawnDefaultPawnfor (NewPlayer, StartSpot);
2017-10-20 02:00:49 +00:00
if (NewPlayer.Pawn == None)
{
NewPlayer.GotoState('Dead');
2020-11-28 20:04:55 +00:00
if (PlayerController(NewPlayer) != None)
2017-10-20 02:00:49 +00:00
PlayerController(NewPlayer).ClientGotoState('Dead','Begin');
return false;
}
else
{
// initialize and start it up
2020-11-28 20:12:58 +00:00
if (NavigationPoint(startSpot)!=None)
2017-10-20 02:00:49 +00:00
NewPlayer.Pawn.SetAnchor(NavigationPoint(startSpot));
2020-11-28 20:04:55 +00:00
if (PlayerController(NewPlayer) != None)
2017-10-20 02:00:49 +00:00
{
PlayerController(NewPlayer).TimeMargin = -0.1;
2020-11-28 20:12:58 +00:00
if (NavigationPoint(startSpot)!=None)
2017-10-20 02:00:49 +00:00
NavigationPoint(startSpot).AnchoredPawn = None; // SetAnchor() will set this since IsHumanControlled() won't return true for the Pawn yet
}
NewPlayer.Pawn.LastStartSpot = PlayerStart(startSpot);
NewPlayer.Pawn.LastStartTime = WorldInfo.TimeSeconds;
NewPlayer.Possess(NewPlayer.Pawn, false);
NewPlayer.Pawn.PlayTeleportEffect(true, true);
NewPlayer.ClientSetRotation(NewPlayer.Pawn.Rotation, TRUE);
2020-11-28 20:04:55 +00:00
if (!WorldInfo.bNoDefaultInventoryForPlayer)
2017-10-20 02:00:49 +00:00
{
AddPlayerSpecificInv(NewPlayer.Pawn);
WorldInfo.Game.AddDefaultInventory(NewPlayer.Pawn);
}
WorldInfo.Game.SetPlayerDefaults(NewPlayer.Pawn);
// activate spawned events
if (WorldInfo.GetGameSequence() != None)
{
WorldInfo.GetGameSequence().FindSeqObjectsByClass(class'SeqEvent_PlayerSpawned',TRUE,Events);
for (Idx = 0; Idx < Events.Length; Idx++)
{
SpawnedEvent = SeqEvent_PlayerSpawned(Events[Idx]);
if (SpawnedEvent != None &&
SpawnedEvent.CheckActivate(NewPlayer,NewPlayer))
{
SpawnedEvent.SpawnPoint = startSpot;
SpawnedEvent.PopulateLinkedVariableValues();
}
}
}
}
KFPC = KFPlayerController(NewPlayer);
KFPRI = KFPlayerReplicationInfo(NewPlayer.PlayerReplicationInfo);
// To fix custom post processing chain when not running in editor or PIE.
if (KFPC != none)
{
LP = LocalPlayer(KFPC.Player);
2020-11-28 20:12:58 +00:00
if (LP != None)
2017-10-20 02:00:49 +00:00
{
LP.RemoveAllPostProcessingChains();
LP.InsertPostProcessingChain(LP.Outer.GetWorldPostProcessChain(),INDEX_NONE,true);
2020-11-28 20:12:58 +00:00
if (KFPC.myHUD != None)
2017-10-20 02:00:49 +00:00
{
KFPC.myHUD.NotifyBindPostProcessEffects();
}
}
}
2020-11-28 20:04:55 +00:00
KFGameInfo(WorldInfo.Game).SetTeam(NewPlayer, KFGameInfo(WorldInfo.Game).Teams[0]);
2017-10-20 02:00:49 +00:00
2020-11-28 20:12:58 +00:00
if (KFPC != none)
2017-10-20 02:00:49 +00:00
{
// Initialize game play post process effects such as damage, low health, etc.
KFPC.InitGameplayPostProcessFX();
}
2020-11-28 20:12:58 +00:00
if (KFPRI!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (KFPRI.Deaths == 0)
2017-10-20 02:00:49 +00:00
KFPRI.Score = KFGameInfo(WorldInfo.Game).DifficultyInfo.GetAdjustedStartingCash();
KFPRI.PlayerHealth = NewPlayer.Pawn.Health;
2020-11-28 20:04:55 +00:00
KFPRI.PlayerHealthPercent = FloatToByte(float(NewPlayer.Pawn.Health) / float(NewPlayer.Pawn.HealthMax));
2017-10-20 02:00:49 +00:00
}
return true;
}
2020-11-28 20:04:55 +00:00
function PlayerBuyStats(ExtPlayerController PC, class<Ext_PerkBase> Perk, int iStat, int Amount)
2017-10-20 02:00:49 +00:00
{
local Ext_PerkBase P;
local int i;
2020-11-28 20:12:58 +00:00
if (bGameHasEnded)
2017-10-20 02:00:49 +00:00
return;
P = PC.ActivePerkManager.FindPerk(Perk);
2020-11-28 20:12:58 +00:00
if (P==None || !P.bPerkNetReady || iStat>=P.PerkStats.Length)
2017-10-20 02:00:49 +00:00
return;
Amount = Min(Amount,P.PerkStats[iStat].MaxValue-P.PerkStats[iStat].CurrentValue);
2020-11-28 20:12:58 +00:00
if (Amount<=0)
2017-10-20 02:00:49 +00:00
return;
i = Amount*P.PerkStats[iStat].CostPerValue;
2020-11-28 20:12:58 +00:00
if (i>P.CurrentSP)
2017-10-20 02:00:49 +00:00
{
Amount = P.CurrentSP/P.PerkStats[iStat].CostPerValue;
2020-11-28 20:12:58 +00:00
if (Amount<=0)
2017-10-20 02:00:49 +00:00
return;
i = Amount*P.PerkStats[iStat].CostPerValue;
}
P.CurrentSP-=i;
2020-11-28 20:12:58 +00:00
if (!P.IncrementStat(iStat,Amount))
2017-10-20 02:00:49 +00:00
PC.ClientMessage("Failed to buy stat.");
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function PlayerChangePerk(ExtPlayerController PC, class<Ext_PerkBase> NewPerk)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (bGameHasEnded)
2017-10-20 02:00:49 +00:00
return;
2020-11-28 20:12:58 +00:00
if (NewPerk==PC.ActivePerkManager.CurrentPerk.Class)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (PC.PendingPerkClass!=None)
2017-10-20 02:00:49 +00:00
{
PC.ClientMessage("You will remain the same perk now.");
PC.PendingPerkClass = None;
}
}
2020-11-28 20:12:58 +00:00
else if (PC.ActivePerkManager.CurrentPerk==None || KFPawn_Customization(PC.Pawn)!=None || (!PC.bSetPerk && KFGameReplicationInfo(WorldInfo.GRI).bTraderIsOpen))
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (PC.ActivePerkManager.ApplyPerkClass(NewPerk))
{
2017-10-20 02:00:49 +00:00
PC.ClientMessage("You have changed your perk to "$NewPerk.Default.PerkName);
PC.bSetPerk = true;
}
2017-10-20 02:00:49 +00:00
else PC.ClientMessage("Invalid perk "$NewPerk.Default.PerkName);
}
2020-11-28 20:12:58 +00:00
else if (PC.bSetPerk)
PC.ClientMessage("Can only change perks once per wave");
2017-10-20 02:00:49 +00:00
else
{
PC.ClientMessage("You will change to perk '"$NewPerk.Default.PerkName$"' during trader time.");
2017-10-20 02:00:49 +00:00
PC.PendingPerkClass = NewPerk;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function CheckPerkChange(ExtPlayerController PC)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (PC.PendingPerkClass!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (PC.ActivePerkManager.ApplyPerkClass(PC.PendingPerkClass))
{
2017-10-20 02:00:49 +00:00
PC.ClientMessage("You have changed your perk to "$PC.PendingPerkClass.Default.PerkName);
PC.bSetPerk = true;
}
2017-10-20 02:00:49 +00:00
else PC.ClientMessage("Invalid perk "$PC.PendingPerkClass.Default.PerkName);
PC.PendingPerkClass = None;
}
}
2020-11-28 21:54:57 +00:00
function Tick(float DeltaTime)
{
local bool bCheckedWave;
local ExtPlayerController ExtPC;
2020-11-28 20:12:58 +00:00
if (KFGameReplicationInfo(WorldInfo.GRI).bTraderIsOpen && !bCheckedWave)
{
foreach WorldInfo.AllControllers(class'ExtPlayerController',ExtPC)
CheckPerkChange(ExtPC);
bCheckedWave = true;
}
2020-11-28 20:12:58 +00:00
else if (bCheckedWave)
bCheckedWave = false;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function PlayerBoughtTrait(ExtPlayerController PC, class<Ext_PerkBase> PerkClass, class<Ext_TraitBase> Trait)
2017-10-20 02:00:49 +00:00
{
local Ext_PerkBase P;
local int i,cost;
2020-11-28 20:12:58 +00:00
if (bGameHasEnded)
2017-10-20 02:00:49 +00:00
return;
P = PC.ActivePerkManager.FindPerk(PerkClass);
2020-11-28 20:12:58 +00:00
if (P==None || !P.bPerkNetReady)
2017-10-20 02:00:49 +00:00
return;
2020-11-28 20:12:58 +00:00
for (i=0; i<P.PerkTraits.Length; ++i)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (P.PerkTraits[i].TraitType==Trait)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (P.PerkTraits[i].CurrentLevel>=Trait.Default.NumLevels)
2017-10-20 02:00:49 +00:00
return;
cost = Trait.Static.GetTraitCost(P.PerkTraits[i].CurrentLevel);
2020-11-28 20:12:58 +00:00
if (cost>P.CurrentSP || !Trait.Static.MeetsRequirements(P.PerkTraits[i].CurrentLevel,P))
2017-10-20 02:00:49 +00:00
return;
PC.ActivePerkManager.bStatsDirty = true;
P.CurrentSP-=cost;
P.bForceNetUpdate = true;
++P.PerkTraits[i].CurrentLevel;
P.ClientReceiveTraitLvl(i,P.PerkTraits[i].CurrentLevel);
2020-11-28 20:12:58 +00:00
if (P.PerkTraits[i].CurrentLevel==1)
P.PerkTraits[i].Data = Trait.Static.Initializefor (P,PC);
2017-10-20 02:00:49 +00:00
2020-11-28 20:12:58 +00:00
if (PC.ActivePerkManager.CurrentPerk==P)
2017-10-20 02:00:49 +00:00
{
Trait.Static.TraitDeActivate(P,P.PerkTraits[i].CurrentLevel-1,P.PerkTraits[i].Data);
Trait.Static.TraitActivate(P,P.PerkTraits[i].CurrentLevel,P.PerkTraits[i].Data);
2020-11-28 20:12:58 +00:00
if (KFPawn_Human(PC.Pawn)!=None)
2017-10-20 02:00:49 +00:00
{
Trait.Static.CancelEffectOn(KFPawn_Human(PC.Pawn),P,P.PerkTraits[i].CurrentLevel-1,P.PerkTraits[i].Data);
Trait.Static.ApplyEffectOn(KFPawn_Human(PC.Pawn),P,P.PerkTraits[i].CurrentLevel,P.PerkTraits[i].Data);
}
}
break;
}
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function PlayerUnloadInfo(ExtPlayerController PC, byte CallID, class<Ext_PerkBase> PerkClass, bool bUnload)
2017-10-20 02:00:49 +00:00
{
local Ext_PerkBase P;
local int LostExp,NewLvl;
// Verify if client tries to cause errors.
2020-11-28 20:12:58 +00:00
if (PC==None || PerkClass==None || PC.ActivePerkManager==None)
2017-10-20 02:00:49 +00:00
return;
// Perk unloading disabled on this server.
2020-11-28 20:12:58 +00:00
if (MinUnloadPerkLevel==-1)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (!bUnload)
2017-10-20 02:00:49 +00:00
PC.ClientGotUnloadInfo(CallID,0);
return;
}
P = PC.ActivePerkManager.FindPerk(PerkClass);
2020-11-28 20:12:58 +00:00
if (P==None) // More client hack attempts.
2017-10-20 02:00:49 +00:00
return;
2020-11-28 20:12:58 +00:00
if (P.CurrentLevel<MinUnloadPerkLevel) // Verify minimum level.
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (!bUnload)
2017-10-20 02:00:49 +00:00
PC.ClientGotUnloadInfo(CallID,1,MinUnloadPerkLevel);
return;
}
// Calc how much EXP is lost on this progress.
LostExp = Round(float(P.CurrentEXP) * UnloadPerkExpCost);
2020-11-28 20:12:58 +00:00
if (!bUnload)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (LostExp==0) // Generous server admin!
2017-10-20 02:00:49 +00:00
PC.ClientGotUnloadInfo(CallID,2,0,0);
else
{
// Calc how many levels are dropped.
NewLvl = P.CalcLevelForExp(P.CurrentEXP-LostExp);
PC.ClientGotUnloadInfo(CallID,2,LostExp,P.CurrentLevel-NewLvl);
}
return;
}
P.UnloadStats();
P.CurrentEXP -= LostExp;
P.SetInitialLevel();
PC.ActivePerkManager.PRIOwner.SetLevelProgress(P.CurrentLevel,P.CurrentPrestige,P.MinimumLevel,P.MaximumLevel);
2020-11-28 20:12:58 +00:00
if (PC.Pawn!=None)
2017-10-20 02:00:49 +00:00
PC.Pawn.Suicide();
}
2020-11-28 20:04:55 +00:00
function ResetPlayerPerk(ExtPlayerController PC, class<Ext_PerkBase> PerkClass, bool bPrestige)
2017-10-20 02:00:49 +00:00
{
local Ext_PerkBase P;
2020-11-28 20:12:58 +00:00
if (bGameHasEnded)
2017-10-20 02:00:49 +00:00
return;
P = PC.ActivePerkManager.FindPerk(PerkClass);
2020-11-28 20:12:58 +00:00
if (P==None || !P.bPerkNetReady)
2017-10-20 02:00:49 +00:00
return;
2020-11-28 20:12:58 +00:00
if (bPrestige)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (!P.CanPrestige())
2017-10-20 02:00:49 +00:00
{
PC.ClientMessage("Prestige for this perk is not allowed.");
return;
}
++P.CurrentPrestige;
}
P.FullReset(bPrestige);
}
function bool CheckReplacement(Actor Other)
{
2020-11-28 20:12:58 +00:00
if (bNoBoomstickJumping && KFWeap_Shotgun_DoubleBarrel(Other)!=None)
2017-10-20 02:00:49 +00:00
KFWeap_Shotgun_DoubleBarrel(Other).DoubleBarrelKickMomentum = 5.f;
return true;
}
2020-11-28 20:04:55 +00:00
final function InitCustomChars(ExtPlayerReplicationInfo PRI)
2017-10-20 02:00:49 +00:00
{
PRI.CustomCharList = CustomCharList;
}
2020-11-28 20:04:55 +00:00
final function bool HasPrivs(ExtPlayerReplicationInfo P)
2017-10-20 02:00:49 +00:00
{
return WorldInfo.NetMode==NM_StandAlone || (P!=None && P.ShowAdminName() && (P.AdminType<=1 || P.AdminType==255));
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function AdminCommand(ExtPlayerController PC, int PlayerID, int Action)
2017-10-20 02:00:49 +00:00
{
local ExtPlayerController E;
local int i;
2020-11-28 20:12:58 +00:00
if (bNoAdminCommands)
2017-10-20 02:00:49 +00:00
{
PC.ClientMessage("Admin level commands are disabled.",'Priority');
return;
}
2020-11-28 20:12:58 +00:00
if (!HasPrivs(ExtPlayerReplicationInfo(PC.PlayerReplicationInfo)))
2017-10-20 02:00:49 +00:00
{
PC.ClientMessage("You do not have enough admin priveleges.",'Priority');
return;
}
foreach WorldInfo.AllControllers(class'ExtPlayerController',E)
2020-11-28 20:12:58 +00:00
if (E.PlayerReplicationInfo.PlayerID==PlayerID)
2017-10-20 02:00:49 +00:00
break;
2020-11-28 20:12:58 +00:00
if (E==None)
2017-10-20 02:00:49 +00:00
{
PC.ClientMessage("Action failed, missing playerID: "$PlayerID,'Priority');
return;
}
2020-11-28 20:12:58 +00:00
if (Action>=100) // Set perk level.
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (E.ActivePerkManager.CurrentPerk==None)
2017-10-20 02:00:49 +00:00
{
PC.ClientMessage(E.PlayerReplicationInfo.PlayerName$" has no perk selected!!!",'Priority');
return;
}
2020-11-28 20:12:58 +00:00
if (Action>=100000) // Set prestige level.
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (E.ActivePerkManager.CurrentPerk.MinLevelForPrestige<0)
2017-10-20 02:00:49 +00:00
{
PC.ClientMessage("Perk "$E.ActivePerkManager.CurrentPerk.Default.PerkName$" has prestige disabled!",'Priority');
return;
}
Action = Min(Action-100000,E.ActivePerkManager.CurrentPerk.MaxPrestige);
E.ActivePerkManager.CurrentPerk.CurrentPrestige = Action;
PC.ClientMessage("Set "$E.PlayerReplicationInfo.PlayerName$"' perk "$E.ActivePerkManager.CurrentPerk.Default.PerkName$" prestige level to "$Action,'Priority');
E.ActivePerkManager.CurrentPerk.FullReset(true);
}
else
{
Action = Clamp(Action-100,E.ActivePerkManager.CurrentPerk.MinimumLevel,E.ActivePerkManager.CurrentPerk.MaximumLevel);
E.ActivePerkManager.CurrentPerk.CurrentEXP = E.ActivePerkManager.CurrentPerk.GetNeededExp(Action-1);
PC.ClientMessage("Set "$E.PlayerReplicationInfo.PlayerName$"' perk "$E.ActivePerkManager.CurrentPerk.Default.PerkName$" level to "$Action,'Priority');
E.ActivePerkManager.CurrentPerk.SetInitialLevel();
E.ActivePerkManager.CurrentPerk.UpdatePRILevel();
}
return;
}
2020-11-28 20:12:58 +00:00
switch (Action)
2017-10-20 02:00:49 +00:00
{
case 0: // Reset ALL Stats
2020-11-28 20:12:58 +00:00
for (i=0; i<E.ActivePerkManager.UserPerks.Length; ++i)
2017-10-20 02:00:49 +00:00
E.ActivePerkManager.UserPerks[i].FullReset();
PC.ClientMessage("Reset EVERY perk for "$E.PlayerReplicationInfo.PlayerName,'Priority');
break;
case 1: // Reset Current Perk Stats
2020-11-28 20:12:58 +00:00
if (E.ActivePerkManager.CurrentPerk!=None)
2017-10-20 02:00:49 +00:00
{
E.ActivePerkManager.CurrentPerk.FullReset();
PC.ClientMessage("Reset perk "$E.ActivePerkManager.CurrentPerk.Default.PerkName$" for "$E.PlayerReplicationInfo.PlayerName,'Priority');
}
else PC.ClientMessage(E.PlayerReplicationInfo.PlayerName$" has no perk selected!!!",'Priority');
break;
case 2: // Add 1,000 XP
case 3: // Add 10,000 XP
case 4: // Advance Perk Level
2020-11-28 20:12:58 +00:00
if (E.ActivePerkManager.CurrentPerk!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (Action==2)
2017-10-20 02:00:49 +00:00
i = 1000;
2020-11-28 20:12:58 +00:00
else if (Action==3)
2017-10-20 02:00:49 +00:00
i = 10000;
else i = Max(E.ActivePerkManager.CurrentPerk.NextLevelEXP - E.ActivePerkManager.CurrentPerk.CurrentEXP,0);
E.ActivePerkManager.EarnedEXP(i);
PC.ClientMessage("Gave "$i$" XP for "$E.PlayerReplicationInfo.PlayerName,'Priority');
}
else PC.ClientMessage(E.PlayerReplicationInfo.PlayerName$" has no perk selected!!!",'Priority');
break;
case 5: // Unload all stats
2020-11-28 20:12:58 +00:00
if (E.ActivePerkManager.CurrentPerk!=None)
2017-10-20 02:00:49 +00:00
{
E.ActivePerkManager.CurrentPerk.UnloadStats(1);
PC.ClientMessage("Unloaded all stats for "$E.PlayerReplicationInfo.PlayerName,'Priority');
}
else PC.ClientMessage(E.PlayerReplicationInfo.PlayerName$" has no perk selected!!!",'Priority');
break;
case 6: // Unload all traits
2020-11-28 20:12:58 +00:00
if (E.ActivePerkManager.CurrentPerk!=None)
2017-10-20 02:00:49 +00:00
{
E.ActivePerkManager.CurrentPerk.UnloadStats(2);
PC.ClientMessage("Unloaded all traits for "$E.PlayerReplicationInfo.PlayerName,'Priority');
}
else PC.ClientMessage(E.PlayerReplicationInfo.PlayerName$" has no perk selected!!!",'Priority');
break;
case 7: // Remove 1,000 XP
case 8: // Remove 10,000 XP
2020-11-28 20:12:58 +00:00
if (E.ActivePerkManager.CurrentPerk!=None)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (Action==6)
2017-10-20 02:00:49 +00:00
i = 1000;
else i = 10000;
E.ActivePerkManager.CurrentPerk.CurrentEXP = Max(E.ActivePerkManager.CurrentPerk.CurrentEXP-i,0);
PC.ClientMessage("Removed "$i$" XP from "$E.PlayerReplicationInfo.PlayerName,'Priority');
}
else PC.ClientMessage(E.PlayerReplicationInfo.PlayerName$" has no perk selected!!!",'Priority');
break;
case 9: // Show Debug Info
PC.ClientMessage("DEBUG info for "$E.PlayerReplicationInfo.PlayerName,'Priority');
PC.ClientMessage("PerkManager "$E.ActivePerkManager$" Current Perk: "$E.ActivePerkManager.CurrentPerk,'Priority');
PC.ClientMessage("Perks Count: "$E.ActivePerkManager.UserPerks.Length,'Priority');
2020-11-28 20:12:58 +00:00
for (i=0; i<E.ActivePerkManager.UserPerks.Length; ++i)
2017-10-20 02:00:49 +00:00
PC.ClientMessage("Perk "$i$": "$E.ActivePerkManager.UserPerks[i]$" XP:"$E.ActivePerkManager.UserPerks[i].CurrentEXP$" Lv:"$E.ActivePerkManager.UserPerks[i].CurrentLevel$" Rep:"$E.ActivePerkManager.UserPerks[i].bPerkNetReady,'Priority');
break;
default:
PC.ClientMessage("Unknown admin action.",'Priority');
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function AdminSetMOTD(ExtPlayerController PC, string S)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (!HasPrivs(ExtPlayerReplicationInfo(PC.PlayerReplicationInfo)))
2017-10-20 02:00:49 +00:00
return;
ServerMOTD = S;
SaveConfig();
PC.ClientMessage("Message of the Day updated.",'Priority');
}
2020-11-28 20:04:55 +00:00
function PlayerChangeSpec(ExtPlayerController PC, bool bSpectator)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (bSpectator==PC.PlayerReplicationInfo.bOnlySpectator || PC.NextSpectateChange>WorldInfo.TimeSeconds)
2017-10-20 02:00:49 +00:00
return;
PC.NextSpectateChange = WorldInfo.TimeSeconds+0.5;
2020-11-28 20:12:58 +00:00
if (WorldInfo.Game.bGameEnded)
2017-10-20 02:00:49 +00:00
PC.ClientMessage("Can't change spectate mode after end-game.");
2020-11-28 20:12:58 +00:00
else if (WorldInfo.Game.bWaitingToStartMatch)
2017-10-20 02:00:49 +00:00
PC.ClientMessage("Can't change spectate mode before game has started.");
2020-11-28 20:12:58 +00:00
else if (WorldInfo.Game.AtCapacity(bSpectator,PC.PlayerReplicationInfo.UniqueId))
2017-10-20 02:00:49 +00:00
PC.ClientMessage("Can't change spectate mode because game is at its maximum capacity.");
2020-11-28 20:12:58 +00:00
else if (bSpectator)
2017-10-20 02:00:49 +00:00
{
PC.NextSpectateChange = WorldInfo.TimeSeconds+2.5;
2020-11-28 20:12:58 +00:00
if (PC.PlayerReplicationInfo.Team!=None)
2017-10-20 02:00:49 +00:00
PC.PlayerReplicationInfo.Team.RemoveFromTeam(PC);
PC.PlayerReplicationInfo.bOnlySpectator = true;
2020-11-28 20:12:58 +00:00
if (PC.Pawn!=None)
2017-10-20 02:00:49 +00:00
PC.Pawn.KilledBy(None);
PC.Reset();
--WorldInfo.Game.NumPlayers;
++WorldInfo.Game.NumSpectators;
WorldInfo.Game.Broadcast(PC,PC.PlayerReplicationInfo.GetHumanReadableName()@"became a spectator");
RemoveRespawn(PC);
}
else
{
PC.PlayerReplicationInfo.bOnlySpectator = false;
2020-11-28 20:12:58 +00:00
if (!WorldInfo.Game.ChangeTeam(PC,WorldInfo.Game.PickTeam(0,PC,PC.PlayerReplicationInfo.UniqueId),false))
2017-10-20 02:00:49 +00:00
{
PC.PlayerReplicationInfo.bOnlySpectator = true;
PC.ClientMessage("Can't become an active player, failed to set a team.");
return;
}
PC.NextSpectateChange = WorldInfo.TimeSeconds+2.5;
++WorldInfo.Game.NumPlayers;
--WorldInfo.Game.NumSpectators;
PC.Reset();
WorldInfo.Game.Broadcast(PC,PC.PlayerReplicationInfo.GetHumanReadableName()@"became an active player");
2020-11-28 20:12:58 +00:00
if (bRespawnCheck)
2017-10-20 02:00:49 +00:00
CheckRespawn(PC);
}
}
2020-11-28 20:04:55 +00:00
function bool GetNextItem(ExtPlayerReplicationInfo PRI, int RepIndex)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (RepIndex>=CustomItemList.Length)
2017-10-20 02:00:49 +00:00
return false;
PRI.ClientAddTraderItem(RepIndex,CustomItemList[RepIndex]);
2017-10-20 02:00:49 +00:00
return true;
}
2020-11-28 20:04:55 +00:00
function InitWebAdmin(ExtWebAdmin_UI UI)
2017-10-20 02:00:49 +00:00
{
local int i;
UI.AddSettingsPage("Main Server Ext",Class,WebConfigs,WebAdminGetValue,WebAdminSetValue);
2020-11-28 20:12:58 +00:00
for (i=0; i<LoadedPerks.Length; ++i)
2017-10-20 02:00:49 +00:00
LoadedPerks[i].Static.InitWebAdmin(UI);
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function string WebAdminGetValue(name PropName, int ElementIndex)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
switch (PropName)
2017-10-20 02:00:49 +00:00
{
case 'StatFileDir':
return StatFileDir;
case 'ForcedMaxPlayers':
return string(ForcedMaxPlayers);
case 'PlayerRespawnTime':
return string(PlayerRespawnTime);
case 'StatAutoSaveWaves':
return string(StatAutoSaveWaves);
case 'PostGameRespawnCost':
return string(PostGameRespawnCost);
case 'bKillMessages':
return string(bKillMessages);
case 'LargeMonsterHP':
return string(LargeMonsterHP);
case 'bDamageMessages':
return string(bDamageMessages);
case 'bEnableMapVote':
return string(bEnableMapVote);
case 'bNoBoomstickJumping':
return string(bNoBoomstickJumping);
case 'bNoAdminCommands':
return string(bNoAdminCommands);
case 'bDumpXMLStats':
return string(bDumpXMLStats);
case 'bRagdollFromFall':
return string(bRagdollFromFall);
case 'bRagdollFromMomentum':
return string(bRagdollFromMomentum);
case 'bRagdollFromBackhit':
return string(bRagdollFromBackhit);
case 'bAddCountryTags':
return string(bAddCountryTags);
case 'MaxTopPlayers':
return string(MaxTopPlayers);
case 'MinUnloadPerkLevel':
return string(MinUnloadPerkLevel);
case 'bDontUseOriginalWeaponry':
return string(bDontUseOriginalWeaponry);
case 'bDisableCustomTrader':
return string(bDisableCustomTrader);
case 'bAllowStandartPistolUpgrade':
return string(bAllowStandartPistolUpgrade);
2017-10-20 02:00:49 +00:00
case 'UnloadPerkExpCost':
return string(UnloadPerkExpCost);
case 'PerkClasses':
return (ElementIndex==-1 ? string(PerkClasses.Length) : PerkClasses[ElementIndex]);
case 'CustomChars':
return (ElementIndex==-1 ? string(CustomChars.Length) : CustomChars[ElementIndex]);
case 'AdminCommands':
return (ElementIndex==-1 ? string(AdminCommands.Length) : AdminCommands[ElementIndex]);
case 'CustomItems':
return (ElementIndex==-1 ? string(CustomItems.Length) : CustomItems[ElementIndex]);
case 'ServerMOTD':
return Repl(ServerMOTD,"|",Chr(10));
case 'BonusGameSongs':
return (ElementIndex==-1 ? string(BonusGameSongs.Length) : BonusGameSongs[ElementIndex]);
case 'BonusGameFX':
return (ElementIndex==-1 ? string(BonusGameFX.Length) : BonusGameFX[ElementIndex]);
case 'bThrowAllWeaponsOnDeath':
return string(bThrowAllWeaponsOnDeath);
2017-10-20 02:00:49 +00:00
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function UpdateArray(out array<string> Ar, int Index, const out string Value)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (Value=="#DELETE")
2017-10-20 02:00:49 +00:00
Ar.Remove(Index,1);
else
{
2020-11-28 20:12:58 +00:00
if (Index>=Ar.Length)
2017-10-20 02:00:49 +00:00
Ar.Length = Index+1;
Ar[Index] = Value;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function WebAdminSetValue(name PropName, int ElementIndex, string Value)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
switch (PropName)
2017-10-20 02:00:49 +00:00
{
case 'StatFileDir':
StatFileDir = Value; break;
case 'ForcedMaxPlayers':
ForcedMaxPlayers = int(Value); break;
case 'PlayerRespawnTime':
PlayerRespawnTime = int(Value); break;
case 'StatAutoSaveWaves':
StatAutoSaveWaves = int(Value); break;
case 'PostGameRespawnCost':
PostGameRespawnCost = int(Value); break;
case 'bKillMessages':
bKillMessages = bool(Value); break;
case 'LargeMonsterHP':
LargeMonsterHP = int(Value); break;
case 'MinUnloadPerkLevel':
MinUnloadPerkLevel = int(Value); break;
case 'UnloadPerkExpCost':
UnloadPerkExpCost = float(Value); break;
case 'bDamageMessages':
bDamageMessages = bool(Value); break;
case 'bEnableMapVote':
bEnableMapVote = bool(Value); break;
case 'bNoAdminCommands':
bNoAdminCommands = bool(Value); break;
case 'bDumpXMLStats':
bDumpXMLStats = bool(Value); break;
case 'bNoBoomstickJumping':
bNoBoomstickJumping = bool(Value); break;
case 'bRagdollFromFall':
bRagdollFromFall = bool(Value); break;
case 'bRagdollFromMomentum':
bRagdollFromMomentum = bool(Value); break;
case 'bRagdollFromBackhit':
bRagdollFromBackhit = bool(Value); break;
case 'bDontUseOriginalWeaponry':
bDontUseOriginalWeaponry = bool(Value); break;
case 'bDisableCustomTrader':
bDisableCustomTrader = bool(Value); break;
case 'bAllowStandartPistolUpgrade':
bAllowStandartPistolUpgrade = bool(Value); break;
2017-10-20 02:00:49 +00:00
case 'bAddCountryTags':
bAddCountryTags = bool(Value); break;
case 'MaxTopPlayers':
MaxTopPlayers = int(Value); break;
case 'ServerMOTD':
ServerMOTD = Repl(Value,Chr(13)$Chr(10),"|"); break;
case 'PerkClasses':
UpdateArray(PerkClasses,ElementIndex,Value); break;
case 'CustomChars':
UpdateArray(CustomChars,ElementIndex,Value); break;
case 'AdminCommands':
UpdateArray(AdminCommands,ElementIndex,Value); break;
case 'CustomItems':
UpdateArray(CustomItems,ElementIndex,Value); break;
case 'BonusGameSongs':
UpdateArray(BonusGameSongs,ElementIndex,Value); break;
case 'BonusGameFX':
UpdateArray(BonusGameFX,ElementIndex,Value); break;
case 'bThrowAllWeaponsOnDeath':
bThrowAllWeaponsOnDeath = bool(Value); break;
2017-10-20 02:00:49 +00:00
default:
return;
}
SaveConfig();
}
defaultproperties
{
// Main devs
DevList.Add("0x0110000100E8984E") // Marco
DevList.Add("0x01100001023DF8A8") // ForrestMarkX
// Some fixes and changes
DevList.Add("0x011000010AF1C7CA") // inklesspen
DevList.Add("0x011000010276FBCB") // GenZmeY
2017-10-20 02:00:49 +00:00
WebConfigs.Add((PropType=0,PropName="StatFileDir",UIName="Stat File Dir",UIDesc="Location of the stat files on the HDD (%s = unique player ID)"))
WebConfigs.Add((PropType=0,PropName="ForcedMaxPlayers",UIName="Server Max Players",UIDesc="A forced max players value of the server (0 = use standard KF2 setting)"))
WebConfigs.Add((PropType=0,PropName="PlayerRespawnTime",UIName="Respawn Time",UIDesc="Players respawn time in seconds after they die (0 = no respawning)"))
WebConfigs.Add((PropType=0,PropName="PostGameRespawnCost",UIName="Post-Game Respawn Cost",UIDesc="Amount of dosh it'll cost to be respawned after end-game (only for custom gametypes that support this)."))
WebConfigs.Add((PropType=0,PropName="StatAutoSaveWaves",UIName="Stat Auto-Save Waves",UIDesc="How often should stats be auto-saved (1 = every wave, 2 = every second wave etc)"))
WebConfigs.Add((PropType=0,PropName="MinUnloadPerkLevel",UIName="Min Unload Perk Level",UIDesc="Minimum level a player should be on before they can use the perk stat unload (-1 = never)."))
WebConfigs.Add((PropType=0,PropName="UnloadPerkExpCost",UIName="Perk Unload XP Cost",UIDesc="The percent of XP it costs for a player to use a perk unload (1 = all XP, 0 = none)."))
WebConfigs.Add((PropType=1,PropName="bKillMessages",UIName="Show Kill Messages",UIDesc="Display on players HUD a kill counter every time they kill something"))
WebConfigs.Add((PropType=0,PropName="LargeMonsterHP",UIName="Large Monster HP",UIDesc="If the enemy kill a monster with more HP then this, broadcast kill message to everyone"))
WebConfigs.Add((PropType=1,PropName="bDamageMessages",UIName="Show Damage Messages",UIDesc="Display on players HUD a damage counter every time they damage an enemy"))
WebConfigs.Add((PropType=1,PropName="bEnableMapVote",UIName="Enable MapVote",UIDesc="Enable MapVote X on this server"))
WebConfigs.Add((PropType=1,PropName="bNoBoomstickJumping",UIName="No Boomstick Jumps",UIDesc="Disable boomstick knockback, so people can't glitch with it on maps"))
WebConfigs.Add((PropType=1,PropName="bNoAdminCommands",UIName="Disable Admin menu",UIDesc="Disable admin menu commands so admins can't modify XP or levels of players"))
WebConfigs.Add((PropType=1,PropName="bDumpXMLStats",UIName="Dump XML stats",UIDesc="Dump XML stat files for some external stat loggers"))
WebConfigs.Add((PropType=1,PropName="bRagdollFromFall",UIName="Ragdoll From Fall",UIDesc="Make players ragdoll if they fall from a high place"))
WebConfigs.Add((PropType=1,PropName="bRagdollFromMomentum",UIName="Ragdoll From Momentum",UIDesc="Make players ragdoll if they take a damage with high momentum transfer"))
WebConfigs.Add((PropType=1,PropName="bRagdollFromBackhit",UIName="Ragdoll From Backhit",UIDesc="Make players ragdoll if they take a big hit to their back"))
WebConfigs.Add((PropType=1,PropName="bAddCountryTags",UIName="Add Country Tags",UIDesc="Add player country tags to their names"))
WebConfigs.Add((PropType=1,PropName="bThrowAllWeaponsOnDeath",UIName="Throw all weapons on death",UIDesc="Forces players to throw all their weapons on death"))
2017-10-20 02:00:49 +00:00
WebConfigs.Add((PropType=0,PropName="MaxTopPlayers",UIName="Max top players",UIDesc="Maximum top players to broadcast of and to keep track of."))
WebConfigs.Add((PropType=2,PropName="PerkClasses",UIName="Perk Classes",UIDesc="List of RPG perks players can play as (careful with removing them, because any perks removed will permanently delete the gained XP for every player for that perk)!",NumElements=-1))
WebConfigs.Add((PropType=2,PropName="CustomChars",UIName="Custom Chars",UIDesc="List of custom characters for this server (prefix with * to mark as admin character).",NumElements=-1))
WebConfigs.Add((PropType=2,PropName="AdminCommands",UIName="Admin Commands",UIDesc="List of Admin commands to show on scoreboard UI for admins (use : to split actual command with display name for the command)",NumElements=-1))
WebConfigs.Add((PropType=3,PropName="ServerMOTD",UIName="MOTD",UIDesc="Message of the Day"))
WebConfigs.Add((PropType=2,PropName="BonusGameSongs",UIName="Bonus Game Songs",UIDesc="List of custom musics to play during level change pong game.",NumElements=-1))
WebConfigs.Add((PropType=2,PropName="BonusGameFX",UIName="Bonus Game FX",UIDesc="List of custom FX to play on pong game.",NumElements=-1))
WebConfigs.Add((PropType=1,PropName="bDisableCustomTrader",UIName="Disable custom trader",UIDesc="Warning! That option will disable all settings below"))
WebConfigs.Add((PropType=2,PropName="CustomItems",UIName="Custom Inventory",UIDesc="List of custom inventory to add to trader (must be KFWeaponDefinition class).",NumElements=-1))
WebConfigs.Add((PropType=1,PropName="bDontUseOriginalWeaponry",UIName="Disable original weapons",UIDesc="Allows to buy default weapons"))
WebConfigs.Add((PropType=1,PropName="bAllowStandartPistolUpgrade",UIName="Standard pistol upgrades",UIDesc="Allows to upgrade standard pistol"))
2017-10-21 16:12:14 +00:00
}