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 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 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 ;
2020-06-23 20:38:04 +00:00
const SettingsTagVer = 13 ;
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 ;
2020-01-09 11:05:13 +00:00
var config bool bServerPerksMode ;
2020-06-23 20:38:04 +00:00
var config bool bDLCWeaponsForFree ;
var config bool bDontUseOriginalWeaponry ;
var config bool bAllowStandartPistolUpgrade ;
var config bool bDisableCustomTrader ;
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 ;
2020-06-23 12:48:24 +00:00
local KFPickupFactory _Item ItemFactory ;
2017-10-20 02:00:49 +00:00
Super . PostBeginPlay ( ) ;
if ( WorldInfo . Game . BaseMutator == None )
WorldInfo . Game . BaseMutator = Self ;
else WorldInfo . Game . BaseMutator . AddMutator ( Self ) ;
if ( bDeleteMe ) // This was a duplicate instance of the mutator.
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 ;
for ( i = 0 ; i < DevList . Length ; ++ i )
{
class 'OnlineSubsystem' . Static . StringToUniqueNetId ( DevList [ i ] , Id ) ;
DevNetID [ i ] = Id ;
}
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' ;
2020-06-23 20:38:04 +00:00
// trader things
if ( ! bDisableCustomTrader && CustomTrader == None )
{
CustomTrader = class 'ExtPlayerReplicationInfo' . Static . CreateNewList ( ) ;
SetTimer ( 0.001 , false , 'EditTraiderItems' ) ;
}
2020-06-23 12:48:24 +00:00
2017-10-20 02:00:49 +00:00
if ( ServerMOTD == "" )
ServerMOTD = "Message of the Day" ;
if ( StatFileDir == "" )
{
StatFileDir = "../../KFGame/Script/%s.usa" ;
Default . StatFileDir = "../../KFGame/Script/%s.usa" ;
}
if ( SettingsInit != SettingsTagVer )
{
if ( SettingsInit == 0 )
ForcedMaxPlayers = 6 ;
if ( SettingsInit < 2 )
{
bKillMessages = true ;
bDamageMessages = true ;
LargeMonsterHP = 800 ;
}
if ( SettingsInit < 3 )
bEnableMapVote = true ;
if ( SettingsInit < 5 )
{
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' ) ;
}
else if ( SettingsInit < 11 )
{
PerkClasses . AddItem ( PathName ( class 'Ext_PerkSharpshooter' ) ) ;
PerkClasses . AddItem ( PathName ( class 'Ext_PerkSWAT' ) ) ;
PerkClasses . AddItem ( PathName ( class 'Ext_PerkSurvivalist' ) ) ;
}
else if ( SettingsInit == 11 )
PerkClasses . AddItem ( PathName ( class 'Ext_PerkSurvivalist' ) ) ;
if ( SettingsInit < 6 )
{
MinUnloadPerkLevel = 25 ;
UnloadPerkExpCost = 0.1 ;
}
if ( SettingsInit < 8 )
{
AdminCommands . Length = 2 ;
AdminCommands [ 0 ] = "Kick:Kick Player" ;
AdminCommands [ 1 ] = "KickBan:Kick-Ban Player" ;
}
if ( SettingsInit < 9 )
MaxTopPlayers = 50 ;
2020-06-23 20:38:04 +00:00
if ( SettingsInit < 13 )
{
bDLCWeaponsForFree = True ;
bAllowStandartPistolUpgrade = True ;
bDisableCustomTrader = False ;
}
2017-10-20 02:00:49 +00:00
SettingsInit = SettingsTagVer ;
SaveConfig ( ) ;
}
for ( i = 0 ; i < PerkClasses . Length ; ++ i )
{
PK = class < Ext _PerkBase > ( DynamicLoadObject ( PerkClasses [ i ] , class 'Class' ) ) ;
if ( PK != None )
{
LoadedPerks . AddItem ( PK ) ;
PK . Static . CheckConfig ( ) ;
}
}
j = 0 ;
for ( i = 0 ; i < CustomChars . Length ; ++ i )
{
bLock = Left ( CustomChars [ i ] , 1 ) == "*" ;
S = ( bLock ? Mid ( CustomChars [ i ] , 1 ) : CustomChars [ i ] ) ;
CH = KFCharacterInfo _Human ( DynamicLoadObject ( S , class 'KFCharacterInfo_Human' , true ) ) ;
if ( CH != None )
{
CustomCharList . Length = j + 1 ;
CustomCharList [ j ] . bLock = bLock ;
CustomCharList [ j ] . Char = CH ;
++ j ;
continue ;
}
OR = ObjectReferencer ( DynamicLoadObject ( S , class 'ObjectReferencer' ) ) ;
if ( OR != None )
{
foreach OR . ReferencedObjects ( O )
{
if ( KFCharacterInfo _Human ( O ) != None )
{
CustomCharList . Length = j + 1 ;
CustomCharList [ j ] . bLock = bLock ;
CustomCharList [ j ] . Char = KFCharacterInfo _Human ( O ) ;
CustomCharList [ j ] . Ref = OR ;
++ j ;
}
}
}
}
// Bonus (pong) game contents.
if ( BonusGameSongs . Length > 0 )
{
BonusGameCue = SoundCue ( DynamicLoadObject ( BonusGameSongs [ Rand ( BonusGameSongs . Length ) ] , class 'SoundCue' ) ) ;
}
if ( BonusGameFX . Length > 0 )
{
BonusGameFXObj = DynamicLoadObject ( BonusGameFX [ Rand ( BonusGameFX . Length ) ] , class 'Object' ) ;
if ( SoundCue ( BonusGameFXObj ) == None && ObjectReferencer ( BonusGameFXObj ) == None ) // Check valid type.
BonusGameFXObj = None ;
}
if ( ForcedMaxPlayers > 0 )
{
SetMaxPlayers ( ) ;
SetTimer ( 0.001 , false , 'SetMaxPlayers' ) ;
}
bRespawnCheck = ( PlayerRespawnTime > 0 ) ;
if ( bRespawnCheck )
SetTimer ( 1 , true ) ;
if ( bEnableMapVote )
{
foreach DynamicActors ( class 'xVotingHandler' , MV )
break ;
if ( MV == None )
MV = Spawn ( class 'xVotingHandler' ) ;
MV . BaseMutator = Class ;
}
SetTimer ( 1 , true , 'CheckWave' ) ;
if ( ! bNoWebAdmin && WorldInfo . NetMode != NM _StandAlone )
SetTimer ( 0.1 , false , 'SetupWebAdmin' ) ;
if ( bDumpXMLStats )
FileOutput = Spawn ( class 'ExtXMLOutput' ) ;
2020-06-23 12:48:24 +00:00
// Disable 9mm and medpistol in all PickupFactories
foreach AllActors ( class 'KFPickupFactory_Item' , ItemFactory )
{
for ( i = 0 ; i < ItemFactory . ItemPickups . Length ; i ++ )
{
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 ;
2020-06-23 20:38:04 +00:00
local KFGFxObject _TraderItems Trad ;
// local FCustomTraderItem CI;
2020-06-23 12:48:24 +00:00
// local STraderItem SI;
2020-06-23 20:38:04 +00:00
// var config bool bDLCWeaponsForFree;
// var config bool bDontUseOriginalWeaponry;
2020-06-23 12:48:24 +00:00
2020-06-23 20:38:04 +00:00
if ( ! bDontUseOriginalWeaponry )
2020-06-23 12:48:24 +00:00
{
2020-06-23 20:38:04 +00:00
Trad = KFGameReplicationInfo ( WorldInfo . GRI ) . TraderItems ;
// Remove dual 9mm, 9mm, medpistol and DLC weapons
for ( i = 0 ; i < Trad . SaleItems . Length ; i ++ )
2020-06-23 12:48:24 +00:00
{
2020-06-23 20:38:04 +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 ;
}
if ( bDLCWeaponsForFree )
{
// DLC Weapons
if ( string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Pistol_Blunderbuss"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Blunt_ChainBat"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Pistol_ChiappaRhino"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Pistol_ChiappaRhinoDual"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Bow_CompoundBow"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Ice_FreezeThrower"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Edged_IonThruster"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Rifle_MosinNagant"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_AssaultRifle_LazerCutter"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_SMG_G18"
|| string ( Trad . SaleItems [ i ] . ClassName ) ~ = "KFWeap_Pistol_DualG18" )
{
continue ;
}
}
// Adding original weapon
AddCIToTraderEx ( Trad . SaleItems [ i ] . WeaponDef ) ;
2020-06-23 12:48:24 +00:00
}
}
// Reinfo and resorting items
2020-06-23 20:38:04 +00:00
// MyKFGI.MyKFGRI.TraderItems.SetItemsInfo(MyKFGI.MyKFGRI.TraderItems.SaleItems);
// MyKFGI.MyKFGRI.TraderItems.SortItemsInfo(MyKFGI.MyKFGRI.TraderItems.SaleItems);
2020-06-23 12:48:24 +00:00
2020-06-23 20:38:04 +00:00
if ( bAllowStandartPistolUpgrade )
2020-06-23 12:48:24 +00:00
{
2020-06-23 20:38:04 +00:00
// Add custom 9mm for upgrades
AddCIToTrader ( "ServerExt.ExtWeapDef_9mm" ) ;
// Add custom medpistol for upgrades
AddCIToTrader ( "ServerExt.ExtWeapDef_MedicPistol" ) ;
2020-06-23 12:48:24 +00:00
}
2020-06-23 20:38:04 +00:00
//Add DLCs weapons for free
if ( bDLCWeaponsForFree )
{
AddCIToTrader ( "ServerExt.DLCWeapDef_Blunderbuss" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_ChainBat" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_ChiappaRhino" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_ChiappaRhinoDual" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_CompoundBow" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_FreezeThrower" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_IonThruster" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_G18" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_MosinNagant" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_LazerCutter" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_Pistol_DualG18" ) ;
AddCIToTrader ( "ServerExt.DLCWeapDef_Pistol_G18C" ) ;
}
2020-06-23 12:48:24 +00:00
// Add custom items from WebAdmin
for ( i = 0 ; i < CustomItems . Length ; ++ i )
{
2020-06-23 20:38:04 +00:00
AddCIToTrader ( CustomItems [ i ] ) ;
2020-06-23 12:48:24 +00:00
}
2020-06-23 20:38:04 +00:00
InitGRIList ( ) ;
}
function AddCIToTrader ( string weapdef )
{
local FCustomTraderItem CI ;
CI . WeaponDef = class < KFWeaponDefinition > ( DynamicLoadObject ( weapdef , class 'Class' ) ) ;
if ( CI . WeaponDef == None )
return ;
CI . WeaponClass = class < KFWeapon > ( DynamicLoadObject ( CI . WeaponDef . Default . WeaponClassPath , class 'Class' ) ) ;
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 ;
if ( CI . WeaponDef == None )
return ;
CI . WeaponClass = class < KFWeapon > ( DynamicLoadObject ( CI . WeaponDef . Default . WeaponClassPath , class 'Class' ) ) ;
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-06-23 12:48:24 +00:00
2017-10-20 02:00:49 +00:00
static final function string GetStatFile ( const out UniqueNetId UID )
{
return Repl ( Default . StatFileDir , "%s" , "U_" $class 'OnlineSubsystem' . Static . UniqueNetIdToString ( UID ) ) ;
}
final function bool IsDev ( const out UniqueNetId UID )
{
local int i ;
for ( i = ( DevNetID . Length - 1 ) ; i >= 0 ; -- i )
if ( DevNetID [ i ] == UID )
return true ;
return false ;
}
function InitGRIList ( )
{
local ExtPlayerController PC ;
KFGameReplicationInfo ( WorldInfo . GRI ) . TraderItems = CustomTrader ;
// Must sync up local client.
if ( WorldInfo . NetMode == NM _StandAlone )
{
foreach LocalPlayerControllers ( class 'ExtPlayerController' , PC )
if ( PC . PurchaseHelper != None )
PC . PurchaseHelper . TraderItems = CustomTrader ;
}
}
function CheckWave ( )
{
if ( KF == None )
{
KF = KFGameReplicationInfo ( WorldInfo . GRI ) ;
if ( KF == None )
return ;
}
if ( LastWaveNum != KF . WaveNum )
{
LastWaveNum = KF . WaveNum ;
NotifyWaveChange ( ) ;
}
if ( ! bGameHasEnded && KF . bMatchIsOver ) // HACK, since KFGameInfo_Survival doesn't properly notify mutators of this!
{
SaveAllPerks ( true ) ;
bGameHasEnded = true ;
}
}
function NotifyWaveChange ( )
{
2017-10-20 07:02:53 +00:00
local ExtPlayerController ExtPC ;
2017-10-20 02:00:49 +00:00
if ( bRespawnCheck )
{
bIsPostGame = ( KF . WaveMax < KF . WaveNum ) ;
bRespawnCheck = ( ! bIsPostGame || PostGameRespawnCost >= 0 ) ;
if ( bRespawnCheck )
SavePlayerInventory ( ) ;
}
if ( StatAutoSaveWaves > 0 && ++ NumWaveSwitches >= StatAutoSaveWaves )
{
NumWaveSwitches = 0 ;
SaveAllPerks ( ) ;
}
2017-10-20 07:02:53 +00:00
if ( ! KF . bTraderIsOpen )
{
foreach WorldInfo . AllControllers ( class 'ExtPlayerController' , ExtPC )
ExtPC . bSetPerk = false ;
}
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 ;
if ( W != None )
{
for ( i = 0 ; ( i < 10 && A == None ) ; ++ i )
A = WebAdmin ( W . ApplicationObjects [ i ] ) ;
if ( A != None )
{
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!");
}
function SetMaxPlayers ( )
{
local OnlineGameSettings GameSettings ;
WorldInfo . Game . MaxPlayers = ForcedMaxPlayers ;
WorldInfo . Game . MaxPlayersAllowed = ForcedMaxPlayers ;
if ( WorldInfo . Game . GameInterface != None )
{
GameSettings = WorldInfo . Game . GameInterface . GetGameSettings ( WorldInfo . Game . PlayerReplicationInfoClass . default . SessionName ) ;
if ( GameSettings != None )
GameSettings . NumPublicConnections = ForcedMaxPlayers ;
}
}
function AddMutator ( Mutator M )
{
if ( M != Self ) // Make sure we don't get added twice.
{
if ( M . Class == Class )
M . Destroy ( ) ;
else Super . AddMutator ( M ) ;
}
}
2020-06-22 04:53:15 +00:00
function bool IsFromMod ( Object O )
{
local string PackageName ;
if ( O == None )
return false ;
PackageName = string ( O . GetPackageName ( ) ) ;
if ( Len ( PackageName ) > 1 && InStr ( Caps ( PackageName ) , "KF" ) == 0 )
{
PackageName = string ( O ) ;
if ( Len ( PackageName ) > 1 && InStr ( Caps ( PackageName ) , "KF" ) == 0 )
return false ;
}
return true ;
}
2017-10-20 02:00:49 +00:00
function ScoreKill ( Controller Killer , Controller Killed )
{
2020-06-22 04:53:15 +00:00
local KFPawn _Monster KFM ;
local int i , j ;
local KFPlayerReplicationInfo DamagerKFPRI ;
local float XP ;
local KFPerk InstigatorPerk ;
local bool cont ;
2017-10-20 07:02:53 +00:00
local KFPlayerController KFPC ;
local ExtPerkManager KillersPerk ;
2017-10-20 02:00:49 +00:00
if ( bRespawnCheck && Killed . bIsPlayer )
CheckRespawn ( Killed ) ;
2020-06-22 04:53:15 +00:00
KFM = KFPawn _Monster ( Killed . Pawn ) ;
if ( KFM != None && Killed . GetTeamNum ( ) != 0 && Killer . bIsPlayer && Killer . GetTeamNum ( ) == 0 )
2017-10-20 02:00:49 +00:00
{
if ( ExtPlayerController ( Killer ) != None && ExtPlayerController ( Killer ) . ActivePerkManager != None )
ExtPlayerController ( Killer ) . ActivePerkManager . PlayerKilled ( KFPawn _Monster ( Killed . Pawn ) , LastKillDamageType ) ;
if ( bKillMessages && Killer . PlayerReplicationInfo != None )
BroadcastKillMessage ( Killed . Pawn , Killer ) ;
2020-06-22 04:53:15 +00:00
if ( KFM . DamageHistory . Length > 0 )
{
for ( i = 0 ; i < KFM . DamageHistory . Length ; i ++ )
{
DamagerKFPRI = KFPlayerReplicationInfo ( KFM . DamageHistory [ i ] . DamagerPRI ) ;
if ( DamagerKFPRI != None )
{
if ( KFM . DamageHistory [ i ] . DamagePerks . Length <= 0 )
{
continue ;
}
cont = true ;
for ( j = 0 ; j < KFM . DamageHistory [ i ] . DamageCausers . Length ; j ++ )
{
if ( IsFromMod ( KFM . DamageHistory [ i ] . DamageCausers [ j ] ) || IsFromMod ( KFM . DamageHistory [ i ] . DamageTypes [ j ] ) )
{
cont = false ;
break ;
}
}
if ( cont && ! IsFromMod ( KFM ) )
continue ;
// Distribute experience points
KFPC = KFPlayerController ( DamagerKFPRI . Owner ) ;
if ( KFPC != none )
{
InstigatorPerk = KFPC . GetPerk ( ) ;
if ( InstigatorPerk . ShouldGetAllTheXP ( ) )
{
KFPC . OnPlayerXPAdded ( KFM . static . GetXPValue ( MyKFGI . GameDifficulty ) , InstigatorPerk . Class ) ;
continue ;
}
XP = KFM . static . GetXPValue ( MyKFGI . GameDifficulty ) / KFM . DamageHistory [ i ] . DamagePerks . Length ;
for ( j = 0 ; j < KFM . DamageHistory [ i ] . DamagePerks . Length ; j ++ )
{
KFPC . OnPlayerXPAdded ( FCeil ( XP ) , KFM . DamageHistory [ i ] . DamagePerks [ j ] ) ;
}
}
}
}
}
2017-10-20 02:00:49 +00:00
}
2017-10-20 07:02:53 +00:00
if ( MyKFGI != None && MyKFGI . IsZedTimeActive ( ) && KFPawn _Monster ( Killed . Pawn ) != 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 ++ ;
}
}
}
2017-10-20 02:00:49 +00:00
if ( ExtPlayerController ( Killed ) != None )
CheckPerkChange ( ExtPlayerController ( Killed ) ) ;
if ( NextMutator != None )
NextMutator . ScoreKill ( Killer , Killed ) ;
2020-06-22 04:53:15 +00:00
else
Super . ScoreKill ( Killer , Killed ) ;
2017-10-20 02:00:49 +00:00
}
function bool PreventDeath ( Pawn Killed , Controller Killer , class < DamageType > damageType , vector HitLocation )
{
if ( ( KFPawn _Human ( Killed ) != None && CheckPreventDeath ( KFPawn _Human ( Killed ) , Killer , damageType ) ) || Super . PreventDeath ( Killed , Killer , damageType , HitLocation ) )
return true ;
LastKillDamageType = damageType ;
if ( Killed . Controller != None && KFPawn _Monster ( Killed ) != None )
{
// Hack for when pet kills a zed.
if ( Killed . GetTeamNum ( ) != 0 )
{
if ( Killer != None && Killer != Killed . Controller && Killer . GetTeamNum ( ) == 0 && Ext _T _MonsterPRI ( Killer . PlayerReplicationInfo ) != None )
GT _PlayerKilled ( Ext _T _MonsterPRI ( Killer . PlayerReplicationInfo ) . OwnerController , Killed . Controller , damageType ) ;
}
// Broadcast pet's deathmessage.
else if ( Killed . PlayerReplicationInfo != None && PlayerController ( Killed . Controller ) == None && damageType != class 'KFDT_Healing' )
BroadcastFFDeath ( Killer , Killed , damageType ) ;
}
return false ;
}
// Replica of KFGameInfo.Killed base.
final function GT _PlayerKilled ( Controller Killer , Controller Killed , class < DamageType > damageType )
{
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 ) ;
if ( KFG != None && KFPC != none && MonsterPawn != none )
{
//Chris: We have to do it earlier here because we need a damage type
2020-01-09 11:05:13 +00:00
KFPC . AddZedKill ( MonsterPawn . class , KFG . GameDifficulty , damageType , false ) ;
2017-10-20 02:00:49 +00:00
2020-06-22 04:53:15 +00:00
// Not support in v1096: KFGameInfo.CheckForBerserkerSmallRadiusKill
2020-06-22 04:47:16 +00:00
//if( KFPC.ActivePerkManager!=none && KFPC.ActivePerkManager.CanEarnSmallRadiusKillXP(damageType) )
// KFG.CheckForBerserkerSmallRadiusKill( MonsterPawn, KFPC );
2017-10-20 02:00:49 +00:00
}
}
final function bool CheckPreventDeath ( KFPawn _Human Victim , Controller Killer , class < DamageType > damageType )
{
local ExtPlayerController E ;
if ( Victim . IsA ( 'KFPawn_Customization' ) )
return false ;
E = ExtPlayerController ( Victim . Controller ) ;
return ( E != None && E . ActivePerkManager != None && E . ActivePerkManager . CurrentPerk != None && E . ActivePerkManager . CurrentPerk . PreventDeath ( Victim , Killer , damageType ) ) ;
}
final function BroadcastKillMessage ( Pawn Killed , Controller Killer )
{
local ExtPlayerController E ;
if ( Killer == None || Killer . PlayerReplicationInfo == None )
return ;
if ( Killed . Default . Health >= LargeMonsterHP )
{
foreach WorldInfo . AllControllers ( class 'ExtPlayerController' , E )
if ( ! E . bClientHideKillMsg )
E . ReceiveKillMessage ( Killed . Class , true , Killer . PlayerReplicationInfo ) ;
}
else if ( ExtPlayerController ( Killer ) != None && ! ExtPlayerController ( Killer ) . bClientHideKillMsg )
ExtPlayerController ( Killer ) . ReceiveKillMessage ( Killed . Class ) ;
}
final function BroadcastFFDeath ( Controller Killer , Pawn Killed , class < DamageType > damageType )
{
local ExtPlayerController E ;
local PlayerReplicationInfo KillerPRI ;
local string P ;
local bool bFF ;
P = Killed . PlayerReplicationInfo . PlayerName ;
if ( Killer == None || Killer == Killed . Controller )
{
foreach WorldInfo . AllControllers ( class 'ExtPlayerController' , E )
E . ClientZedKillMessage ( damageType , P ) ;
return ;
}
bFF = ( Killer . GetTeamNum ( ) == 0 ) ;
KillerPRI = Killer . PlayerReplicationInfo ;
if ( PlayerController ( Killer ) == None )
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 ) ;
if ( LastDamageDealer != None ) // Make sure no other damagers interfear with the old thing going on.
{
ClearTimer ( 'CheckDamageDone' ) ;
CheckDamageDone ( ) ;
}
2017-10-21 16:12:14 +00:00
if ( KFPawn _Monster ( Injured ) != None && InstigatedBy != none && InstigatedBy . GetTeamNum ( ) == Injured . GetTeamNum ( ) )
{
Momentum = vect ( 0 , 0 , 0 ) ;
Damage = 0 ;
return ;
}
2017-10-20 02:00:49 +00:00
if ( Damage > 0 && InstigatedBy != None )
{
2017-10-20 07:02:53 +00:00
if ( KFPawn _Monster ( Injured ) != None )
2017-10-20 02:00:49 +00:00
{
2017-10-20 07:02:53 +00:00
if ( Injured . GetTeamNum ( ) != 0 )
2017-10-20 02:00:49 +00:00
{
2017-10-20 07:02:53 +00:00
LastDamageDealer = ExtPlayerController ( InstigatedBy ) ;
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.
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
}
2017-10-20 07:02:53 +00:00
else if ( KFPawn ( InstigatedBy . Pawn ) . GetTeamNum ( ) != KFPawn ( Injured ) . GetTeamNum ( ) )
2017-10-20 02:00:49 +00:00
{
2017-10-20 07:02:53 +00:00
Momentum = vect ( 0 , 0 , 0 ) ;
Damage = 0 ;
2017-10-20 02:00:49 +00:00
}
}
else if ( bDamageMessages && KFPawn _Human ( Injured ) != None && Injured . GetTeamNum ( ) == 0 && InstigatedBy . GetTeamNum ( ) != 0 && ExtPlayerController ( InstigatedBy ) != None )
{
LastDamageDealer = ExtPlayerController ( InstigatedBy ) ;
if ( bDamageMessages && ! LastDamageDealer . bClientHideNumbers )
{
// Must delay this until next to get accurate damage dealt result.
LastHitZed = KFPawn ( Injured ) ;
LastHitHP = LastHitZed . Health ;
LastDamagePosition = HitLocation ;
SetTimer ( 0.001 , false , 'CheckDamageDone' ) ;
}
}
}
}
final function CheckDamageDone ( )
{
local int Damage ;
if ( LastDamageDealer != None && LastHitZed != None && LastHitHP != LastHitZed . Health )
{
Damage = LastHitHP - Max ( LastHitZed . Health , 0 ) ;
if ( Damage > 0 )
{
if ( ! LastDamageDealer . bClientHideDamageMsg && KFPawn _Monster ( LastHitZed ) != None )
LastDamageDealer . ReceiveDamageMessage ( LastHitZed . Class , Damage ) ;
if ( ! LastDamageDealer . bClientHideNumbers )
LastDamageDealer . ClientNumberMsg ( Damage , LastDamagePosition , DMG _PawnDamage ) ;
}
}
LastDamageDealer = None ;
}
final function HackSetHistory ( KFPawn C , Pawn Injured , Controller Player , int Damage , vector HitLocation )
{
local int i ;
local ExtPlayerController PC ;
if ( Player == None )
return ;
PC = ExtPlayerController ( Player ) ;
if ( bDamageMessages && PC != None )
{
if ( ! PC . bClientHideDamageMsg )
PC . ReceiveDamageMessage ( Injured . Class , Damage ) ;
if ( ! PC . bClientHideNumbers )
PC . ClientNumberMsg ( Damage , HitLocation , DMG _PawnDamage ) ;
}
i = C . DamageHistory . Find ( 'DamagerController' , Player ) ;
if ( i == - 1 )
{
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 ;
}
else if ( ( WorldInfo . TimeSeconds - C . DamageHistory [ i ] . LastTimeDamaged ) < 10 )
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 ( )
{
if ( ! bGameHasEnded )
{
SaveAllPerks ( true ) ;
bGameHasEnded = true ;
}
return Super . HandleRestartGame ( ) ;
}
function NotifyLogout ( Controller Exiting )
{
if ( KFPlayerController ( Exiting ) != None )
RemoveRespawn ( Exiting ) ;
if ( ! bGameHasEnded && ExtPlayerController ( Exiting ) != None )
{
CheckPerkChange ( ExtPlayerController ( Exiting ) ) ;
SavePlayerPerk ( ExtPlayerController ( Exiting ) ) ;
}
if ( NextMutator != None )
NextMutator . NotifyLogout ( Exiting ) ;
}
function NotifyLogin ( Controller NewPlayer )
{
if ( ExtPlayerController ( NewPlayer ) != None )
{
if ( ExtPlayerReplicationInfo ( NewPlayer . PlayerReplicationInfo ) != None )
InitCustomChars ( ExtPlayerReplicationInfo ( NewPlayer . PlayerReplicationInfo ) ) ;
if ( bAddCountryTags && NetConnection ( PlayerController ( NewPlayer ) . Player ) != None )
ExtPlayerReplicationInfo ( NewPlayer . PlayerReplicationInfo ) . SetPlayerNameTag ( class 'CtryDatabase' . Static . GetClientCountryStr ( PlayerController ( NewPlayer ) . GetPlayerNetworkAddress ( ) ) ) ;
ExtPlayerReplicationInfo ( NewPlayer . PlayerReplicationInfo ) . bIsDev = IsDev ( NewPlayer . PlayerReplicationInfo . UniqueId ) ;
if ( WorldInfo . NetMode != NM _StandAlone )
ExtPlayerReplicationInfo ( NewPlayer . PlayerReplicationInfo ) . OnRepNextItem = GetNextItem ;
if ( BonusGameCue != None || BonusGameFXObj != None )
ExtPlayerController ( NewPlayer ) . ClientSetBonus ( BonusGameCue , BonusGameFXObj ) ;
if ( bRespawnCheck )
CheckRespawn ( NewPlayer ) ;
if ( ! bGameHasEnded )
InitializePerks ( ExtPlayerController ( NewPlayer ) ) ;
SendMOTD ( ExtPlayerController ( NewPlayer ) ) ;
}
if ( NextMutator != None )
NextMutator . NotifyLogin ( NewPlayer ) ;
}
final function InitializePerks ( ExtPlayerController Other )
{
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 ( ) ;
for ( i = 0 ; i < LoadedPerks . Length ; ++ i )
{
P = Spawn ( LoadedPerks [ i ] , Other ) ;
PM . RegisterPerk ( P ) ;
}
ServerStatLoader . FlushData ( ) ;
if ( ServerStatLoader . LoadStatFile ( Other ) )
{
ServerStatLoader . ToStart ( ) ;
PM . LoadData ( ServerStatLoader ) ;
if ( Default . MaxTopPlayers > 0 )
class 'ExtStatList' . Static . SetTopPlayers ( Other ) ;
}
PM . ServerInitPerks ( ) ;
PM . InitiateClientRep ( ) ;
}
final function SendMOTD ( ExtPlayerController PC )
{
local string S ;
local int i ;
S = ServerMOTD ;
while ( Len ( S ) > 510 )
{
PC . ReceiveServerMOTD ( Left ( S , 500 ) , false ) ;
S = Mid ( S , 500 ) ;
}
PC . ReceiveServerMOTD ( S , true ) ;
for ( i = 0 ; i < AdminCommands . Length ; ++ i )
PC . AddAdminCmd ( AdminCommands [ i ] ) ;
}
final function SavePlayerPerk ( ExtPlayerController PC )
{
if ( PC . ActivePerkManager != None && PC . ActivePerkManager . bStatsDirty )
{
// Verify broken stats.
if ( PC . ActivePerkManager . bUserStatsBroken )
{
PC . ClientMessage ( "Warning: Your stats are broken, not saving." , 'Priority' ) ;
return ;
}
ServerStatLoader . FlushData ( ) ;
if ( ServerStatLoader . LoadStatFile ( PC ) && ServerStatLoader . GetSaveVersion ( ) != PC . ActivePerkManager . UserDataVersion )
{
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.
if ( FileOutput != None )
FileOutput . DumpXML ( PC . ActivePerkManager ) ;
}
}
function SaveAllPerks ( optional bool bOnEndGame )
{
local ExtPlayerController PC ;
if ( bGameHasEnded )
return ;
foreach WorldInfo . AllControllers ( class 'ExtPlayerController' , PC )
if ( PC . ActivePerkManager != None && PC . ActivePerkManager . bStatsDirty )
{
if ( bOnEndGame )
CheckPerkChange ( PC ) ;
SavePlayerPerk ( PC ) ;
}
}
function CheckRespawn ( Controller PC )
{
if ( ! PC . bIsPlayer || ExtPlayerReplicationInfo ( PC . PlayerReplicationInfo ) == None || PC . PlayerReplicationInfo . bOnlySpectator || WorldInfo . Game . bWaitingToStartMatch || WorldInfo . Game . bGameEnded )
return ;
// VS redead.
if ( ExtHumanPawn ( PC . Pawn ) != None && ExtHumanPawn ( PC . Pawn ) . bPendingRedead )
return ;
if ( bIsPostGame && PC . PlayerReplicationInfo . Score < PostGameRespawnCost )
{
if ( PlayerController ( PC ) != None )
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 ;
if ( PendingSpawners . Find ( PC ) < 0 )
PendingSpawners . AddItem ( PC ) ;
}
function RemoveRespawn ( Controller PC )
{
ExtPlayerReplicationInfo ( PC . PlayerReplicationInfo ) . RespawnCounter = - 1 ;
PendingSpawners . RemoveItem ( PC ) ;
}
final function InitPlayer ( ExtHumanPawn Other )
{
local ExtPlayerReplicationInfo PRI ;
PRI = ExtPlayerReplicationInfo ( Other . PlayerReplicationInfo ) ;
if ( PRI != None && PRI . PerkManager != None && PRI . PerkManager . CurrentPerk != None )
PRI . PerkManager . CurrentPerk . ApplyEffectsTo ( Other ) ;
Other . bRagdollFromFalling = bRagdollFromFall ;
Other . bRagdollFromMomentum = bRagdollFromMomentum ;
Other . bRagdollFromBackhit = bRagdollFromBackhit ;
}
function ModifyPlayer ( Pawn Other )
{
if ( ExtHumanPawn ( Other ) != None )
InitPlayer ( ExtHumanPawn ( Other ) ) ;
if ( NextMutator != None )
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 ) ;
for ( i = 0 ; i < PendingSpawners . Length ; ++ i )
{
PC = PendingSpawners [ i ] ;
if ( bAllDead || PC == None || PC . PlayerReplicationInfo . bOnlySpectator || ( PC . Pawn != None && PC . Pawn . IsAliveAndWell ( ) ) )
{
if ( PC != None )
{
ExtPlayerReplicationInfo ( PC . PlayerReplicationInfo ) . RespawnCounter = - 1 ;
PC . PlayerReplicationInfo . bForceNetUpdate = true ;
}
PendingSpawners . Remove ( i -- , 1 ) ;
}
else if ( bIsPostGame && PC . PlayerReplicationInfo . Score < PostGameRespawnCost )
{
ExtPlayerReplicationInfo ( PC . PlayerReplicationInfo ) . RespawnCounter = - 1 ;
PC . PlayerReplicationInfo . bForceNetUpdate = true ;
if ( PlayerController ( PC ) != None )
PlayerController ( PC ) . ClientMessage ( "You can't afford to respawn anymore (need " $PostGameRespawnCost @ Chr ( 163 ) $ ")!" , 'LowCriticalEvent' ) ;
PendingSpawners . Remove ( i -- , 1 ) ;
}
else if ( -- ExtPlayerReplicationInfo ( PC . PlayerReplicationInfo ) . RespawnCounter <= 0 )
{
PC . PlayerReplicationInfo . bForceNetUpdate = true ;
ExtPlayerReplicationInfo ( PC . PlayerReplicationInfo ) . RespawnCounter = 0 ;
if ( ! bSpawned ) // Spawn only one player at time (so game doesn't crash if many players spawn in same time).
{
bSpawned = true ;
if ( RespawnPlayer ( PC ) )
{
if ( bIsPostGame )
{
if ( PlayerController ( PC ) != None )
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 ;
}
}
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 )
if ( P . IsAliveAndWell ( ) && P . InvManager != None && P . Controller != None && P . Controller . PlayerReplicationInfo != None )
{
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 )
{
if ( KFInventory _Money ( Inv ) != None )
continue ;
K = KFWeapon ( Inv ) ;
if ( K != None && ! K . bCanThrow ) // Skip non-throwable items.
continue ;
PlayerInv [ i ] . Inv . Length = j + 1 ;
PlayerInv [ i ] . Inv [ j ] . ItemClass = Inv . Class ;
if ( K != None )
{
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 ;
}
}
final function bool AddPlayerSpecificInv ( Pawn Other )
{
local int i , j ;
local Inventory Inv ;
local KFWeapon K ;
for ( i = ( PlayerInv . Length - 1 ) ; i >= 0 ; -- i )
if ( PlayerInv [ i ] . OwnerPlayer == Other . Controller )
{
KFInventoryManager ( Other . InvManager ) . bInfiniteWeight = true ;
KFInventoryManager ( Other . InvManager ) . GrenadeCount = PlayerInv [ i ] . Gren ;
for ( j = ( PlayerInv [ i ] . Inv . Length - 1 ) ; j >= 0 ; -- j )
{
Inv = Other . InvManager . FindInventoryType ( PlayerInv [ i ] . Inv [ j ] . ItemClass , false ) ;
if ( Inv == None )
{
Inv = Other . InvManager . CreateInventory ( PlayerInv [ i ] . Inv [ j ] . ItemClass ) ;
}
K = KFWeapon ( Inv ) ;
if ( K != None )
{
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 ] ) ;
}
}
if ( Other . InvManager . FindInventoryType ( class 'KFInventory_Money' , true ) == None )
Other . InvManager . CreateInventory ( class 'KFInventory_Money' ) ;
KFInventoryManager ( Other . InvManager ) . bInfiniteWeight = false ;
return true ;
}
return false ;
}
final function Pawn SpawnDefaultPawnFor ( Controller NewPlayer , Actor StartSpot ) // Clone of GameInfo one, but with Actor StartSpot.
{
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 ;
}
final function bool RespawnPlayer ( Controller NewPlayer )
{
local KFPlayerReplicationInfo KFPRI ;
local KFPlayerController KFPC ;
local Actor startSpot ;
local int Idx ;
local array < SequenceObject > Events ;
local SeqEvent _PlayerSpawned SpawnedEvent ;
local LocalPlayer LP ;
if ( NewPlayer . Pawn != None )
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
NewPlayer . Pawn = SpawnDefaultPawnFor ( NewPlayer , StartSpot ) ;
if ( NewPlayer . Pawn == None )
{
NewPlayer . GotoState ( 'Dead' ) ;
if ( PlayerController ( NewPlayer ) != None )
PlayerController ( NewPlayer ) . ClientGotoState ( 'Dead' , 'Begin' ) ;
return false ;
}
else
{
// initialize and start it up
if ( NavigationPoint ( startSpot ) != None )
NewPlayer . Pawn . SetAnchor ( NavigationPoint ( startSpot ) ) ;
if ( PlayerController ( NewPlayer ) != None )
{
PlayerController ( NewPlayer ) . TimeMargin = - 0.1 ;
if ( NavigationPoint ( startSpot ) != None )
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 ) ;
if ( ! WorldInfo . bNoDefaultInventoryForPlayer )
{
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 ) ;
if ( LP != None )
{
LP . RemoveAllPostProcessingChains ( ) ;
LP . InsertPostProcessingChain ( LP . Outer . GetWorldPostProcessChain ( ) , INDEX _NONE , true ) ;
if ( KFPC . myHUD != None )
{
KFPC . myHUD . NotifyBindPostProcessEffects ( ) ;
}
}
}
KFGameInfo ( WorldInfo . Game ) . SetTeam ( NewPlayer , KFGameInfo ( WorldInfo . Game ) . Teams [ 0 ] ) ;
if ( KFPC != none )
{
// Initialize game play post process effects such as damage, low health, etc.
KFPC . InitGameplayPostProcessFX ( ) ;
}
if ( KFPRI != None )
{
if ( KFPRI . Deaths == 0 )
KFPRI . Score = KFGameInfo ( WorldInfo . Game ) . DifficultyInfo . GetAdjustedStartingCash ( ) ;
KFPRI . PlayerHealth = NewPlayer . Pawn . Health ;
KFPRI . PlayerHealthPercent = FloatToByte ( float ( NewPlayer . Pawn . Health ) / float ( NewPlayer . Pawn . HealthMax ) ) ;
}
return true ;
}
function PlayerBuyStats ( ExtPlayerController PC , class < Ext _PerkBase > Perk , int iStat , int Amount )
{
local Ext _PerkBase P ;
local int i ;
if ( bGameHasEnded )
return ;
P = PC . ActivePerkManager . FindPerk ( Perk ) ;
if ( P == None || ! P . bPerkNetReady || iStat >= P . PerkStats . Length )
return ;
Amount = Min ( Amount , P . PerkStats [ iStat ] . MaxValue - P . PerkStats [ iStat ] . CurrentValue ) ;
if ( Amount <= 0 )
return ;
i = Amount * P . PerkStats [ iStat ] . CostPerValue ;
if ( i > P . CurrentSP )
{
Amount = P . CurrentSP / P . PerkStats [ iStat ] . CostPerValue ;
if ( Amount <= 0 )
return ;
i = Amount * P . PerkStats [ iStat ] . CostPerValue ;
}
P . CurrentSP -= i ;
if ( ! P . IncrementStat ( iStat , Amount ) )
PC . ClientMessage ( "Failed to buy stat." ) ;
}
function PlayerChangePerk ( ExtPlayerController PC , class < Ext _PerkBase > NewPerk )
{
if ( bGameHasEnded )
return ;
if ( NewPerk == PC . ActivePerkManager . CurrentPerk . Class )
{
if ( PC . PendingPerkClass != None )
{
PC . ClientMessage ( "You will remain the same perk now." ) ;
PC . PendingPerkClass = None ;
}
}
2017-10-20 07:02:53 +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
{
if ( PC . ActivePerkManager . ApplyPerkClass ( NewPerk ) )
2017-10-20 07:02:53 +00:00
{
2017-10-20 02:00:49 +00:00
PC . ClientMessage ( "You have changed your perk to " $NewPerk . Default . PerkName ) ;
2017-10-20 07:02:53 +00:00
PC . bSetPerk = true ;
}
2017-10-20 02:00:49 +00:00
else PC . ClientMessage ( "Invalid perk " $NewPerk . Default . PerkName ) ;
}
2017-10-20 07:02:53 +00:00
else if ( PC . bSetPerk )
PC . ClientMessage ( "Can only change perks once per wave" ) ;
2017-10-20 02:00:49 +00:00
else
{
2017-10-20 07:02:53 +00:00
PC . ClientMessage ( "You will change to perk '" $NewPerk . Default . PerkName$ "' during trader time." ) ;
2017-10-20 02:00:49 +00:00
PC . PendingPerkClass = NewPerk ;
}
}
function CheckPerkChange ( ExtPlayerController PC )
{
if ( PC . PendingPerkClass != None )
{
if ( PC . ActivePerkManager . ApplyPerkClass ( PC . PendingPerkClass ) )
2017-10-20 07:02:53 +00:00
{
2017-10-20 02:00:49 +00:00
PC . ClientMessage ( "You have changed your perk to " $PC . PendingPerkClass . Default . PerkName ) ;
2017-10-20 07:02:53 +00:00
PC . bSetPerk = true ;
}
2017-10-20 02:00:49 +00:00
else PC . ClientMessage ( "Invalid perk " $PC . PendingPerkClass . Default . PerkName ) ;
PC . PendingPerkClass = None ;
}
}
2017-10-20 07:02:53 +00:00
function Tick ( float DeltaTime )
{
local bool bCheckedWave ;
local ExtPlayerController ExtPC ;
if ( KFGameReplicationInfo ( WorldInfo . GRI ) . bTraderIsOpen && ! bCheckedWave )
{
foreach WorldInfo . AllControllers ( class 'ExtPlayerController' , ExtPC )
CheckPerkChange ( ExtPC ) ;
bCheckedWave = true ;
}
else if ( bCheckedWave )
bCheckedWave = false ;
}
2017-10-20 02:00:49 +00:00
function PlayerBoughtTrait ( ExtPlayerController PC , class < Ext _PerkBase > PerkClass , class < Ext _TraitBase > Trait )
{
local Ext _PerkBase P ;
local int i , cost ;
if ( bGameHasEnded )
return ;
P = PC . ActivePerkManager . FindPerk ( PerkClass ) ;
if ( P == None || ! P . bPerkNetReady )
return ;
for ( i = 0 ; i < P . PerkTraits . Length ; ++ i )
{
if ( P . PerkTraits [ i ] . TraitType == Trait )
{
if ( P . PerkTraits [ i ] . CurrentLevel >= Trait . Default . NumLevels )
return ;
cost = Trait . Static . GetTraitCost ( P . PerkTraits [ i ] . CurrentLevel ) ;
if ( cost > P . CurrentSP || ! Trait . Static . MeetsRequirements ( P . PerkTraits [ i ] . CurrentLevel , P ) )
return ;
PC . ActivePerkManager . bStatsDirty = true ;
P . CurrentSP -= cost ;
P . bForceNetUpdate = true ;
++ P . PerkTraits [ i ] . CurrentLevel ;
P . ClientReceiveTraitLvl ( i , P . PerkTraits [ i ] . CurrentLevel ) ;
if ( P . PerkTraits [ i ] . CurrentLevel == 1 )
P . PerkTraits [ i ] . Data = Trait . Static . InitializeFor ( P , PC ) ;
if ( PC . ActivePerkManager . CurrentPerk == P )
{
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 ) ;
if ( KFPawn _Human ( PC . Pawn ) != None )
{
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 ;
}
}
}
function PlayerUnloadInfo ( ExtPlayerController PC , byte CallID , class < Ext _PerkBase > PerkClass , bool bUnload )
{
local Ext _PerkBase P ;
local int LostExp , NewLvl ;
// Verify if client tries to cause errors.
if ( PC == None || PerkClass == None || PC . ActivePerkManager == None )
return ;
// Perk unloading disabled on this server.
if ( MinUnloadPerkLevel == - 1 )
{
if ( ! bUnload )
PC . ClientGotUnloadInfo ( CallID , 0 ) ;
return ;
}
P = PC . ActivePerkManager . FindPerk ( PerkClass ) ;
if ( P == None ) // More client hack attempts.
return ;
if ( P . CurrentLevel < MinUnloadPerkLevel ) // Verify minimum level.
{
if ( ! bUnload )
PC . ClientGotUnloadInfo ( CallID , 1 , MinUnloadPerkLevel ) ;
return ;
}
// Calc how much EXP is lost on this progress.
LostExp = Round ( float ( P . CurrentEXP ) * UnloadPerkExpCost ) ;
if ( ! bUnload )
{
if ( LostExp == 0 ) // Generous server admin!
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 ) ;
if ( PC . Pawn != None )
PC . Pawn . Suicide ( ) ;
}
function ResetPlayerPerk ( ExtPlayerController PC , class < Ext _PerkBase > PerkClass , bool bPrestige )
{
local Ext _PerkBase P ;
if ( bGameHasEnded )
return ;
P = PC . ActivePerkManager . FindPerk ( PerkClass ) ;
if ( P == None || ! P . bPerkNetReady )
return ;
if ( bPrestige )
{
if ( ! P . CanPrestige ( ) )
{
PC . ClientMessage ( "Prestige for this perk is not allowed." ) ;
return ;
}
++ P . CurrentPrestige ;
}
P . FullReset ( bPrestige ) ;
}
function bool CheckReplacement ( Actor Other )
{
if ( bNoBoomstickJumping && KFWeap _Shotgun _DoubleBarrel ( Other ) != None )
KFWeap _Shotgun _DoubleBarrel ( Other ) . DoubleBarrelKickMomentum = 5. f ;
return true ;
}
final function InitCustomChars ( ExtPlayerReplicationInfo PRI )
{
PRI . CustomCharList = CustomCharList ;
}
final function bool HasPrivs ( ExtPlayerReplicationInfo P )
{
return WorldInfo . NetMode == NM _StandAlone || ( P != None && P . ShowAdminName ( ) && ( P . AdminType <= 1 || P . AdminType == 255 ) ) ;
}
function AdminCommand ( ExtPlayerController PC , int PlayerID , int Action )
{
local ExtPlayerController E ;
local int i ;
if ( bNoAdminCommands )
{
PC . ClientMessage ( "Admin level commands are disabled." , 'Priority' ) ;
return ;
}
if ( ! HasPrivs ( ExtPlayerReplicationInfo ( PC . PlayerReplicationInfo ) ) )
{
PC . ClientMessage ( "You do not have enough admin priveleges." , 'Priority' ) ;
return ;
}
foreach WorldInfo . AllControllers ( class 'ExtPlayerController' , E )
if ( E . PlayerReplicationInfo . PlayerID == PlayerID )
break ;
if ( E == None )
{
PC . ClientMessage ( "Action failed, missing playerID: " $PlayerID , 'Priority' ) ;
return ;
}
if ( Action >= 100 ) // Set perk level.
{
if ( E . ActivePerkManager . CurrentPerk == None )
{
PC . ClientMessage ( E . PlayerReplicationInfo . PlayerName$ " has no perk selected!!!" , 'Priority' ) ;
return ;
}
if ( Action >= 100000 ) // Set prestige level.
{
if ( E . ActivePerkManager . CurrentPerk . MinLevelForPrestige < 0 )
{
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 ;
}
switch ( Action )
{
case 0 : // Reset ALL Stats
for ( i = 0 ; i < E . ActivePerkManager . UserPerks . Length ; ++ i )
E . ActivePerkManager . UserPerks [ i ] . FullReset ( ) ;
PC . ClientMessage ( "Reset EVERY perk for " $E . PlayerReplicationInfo . PlayerName , 'Priority' ) ;
break ;
case 1 : // Reset Current Perk Stats
if ( E . ActivePerkManager . CurrentPerk != None )
{
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
if ( E . ActivePerkManager . CurrentPerk != None )
{
if ( Action == 2 )
i = 1000 ;
else if ( Action == 3 )
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
if ( E . ActivePerkManager . CurrentPerk != None )
{
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
if ( E . ActivePerkManager . CurrentPerk != None )
{
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
if ( E . ActivePerkManager . CurrentPerk != None )
{
if ( Action == 6 )
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' ) ;
for ( i = 0 ; i < E . ActivePerkManager . UserPerks . Length ; ++ i )
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' ) ;
}
}
function AdminSetMOTD ( ExtPlayerController PC , string S )
{
if ( ! HasPrivs ( ExtPlayerReplicationInfo ( PC . PlayerReplicationInfo ) ) )
return ;
ServerMOTD = S ;
SaveConfig ( ) ;
PC . ClientMessage ( "Message of the Day updated." , 'Priority' ) ;
}
function PlayerChangeSpec ( ExtPlayerController PC , bool bSpectator )
{
if ( bSpectator == PC . PlayerReplicationInfo . bOnlySpectator || PC . NextSpectateChange > WorldInfo . TimeSeconds )
return ;
PC . NextSpectateChange = WorldInfo . TimeSeconds + 0.5 ;
if ( WorldInfo . Game . bGameEnded )
PC . ClientMessage ( "Can't change spectate mode after end-game." ) ;
else if ( WorldInfo . Game . bWaitingToStartMatch )
PC . ClientMessage ( "Can't change spectate mode before game has started." ) ;
else if ( WorldInfo . Game . AtCapacity ( bSpectator , PC . PlayerReplicationInfo . UniqueId ) )
PC . ClientMessage ( "Can't change spectate mode because game is at its maximum capacity." ) ;
else if ( bSpectator )
{
PC . NextSpectateChange = WorldInfo . TimeSeconds + 2.5 ;
if ( PC . PlayerReplicationInfo . Team != None )
PC . PlayerReplicationInfo . Team . RemoveFromTeam ( PC ) ;
PC . PlayerReplicationInfo . bOnlySpectator = true ;
if ( PC . Pawn != None )
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 ;
if ( ! WorldInfo . Game . ChangeTeam ( PC , WorldInfo . Game . PickTeam ( 0 , PC , PC . PlayerReplicationInfo . UniqueId ) , false ) )
{
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" ) ;
if ( bRespawnCheck )
CheckRespawn ( PC ) ;
}
}
function bool GetNextItem ( ExtPlayerReplicationInfo PRI , int RepIndex )
{
if ( RepIndex >= CustomItemList . Length )
return false ;
2020-06-23 20:38:04 +00:00
PRI . ClientAddTraderItem ( RepIndex , CustomItemList [ RepIndex ] ) ;
2017-10-20 02:00:49 +00:00
return true ;
}
function InitWebAdmin ( ExtWebAdmin _UI UI )
{
local int i ;
UI . AddSettingsPage ( "Main Server Ext" , Class , WebConfigs , WebAdminGetValue , WebAdminSetValue ) ;
for ( i = 0 ; i < LoadedPerks . Length ; ++ i )
LoadedPerks [ i ] . Static . InitWebAdmin ( UI ) ;
}
function string WebAdminGetValue ( name PropName , int ElementIndex )
{
switch ( PropName )
{
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 ) ;
2020-06-23 20:38:04 +00:00
case 'bDontUseOriginalWeaponry' :
return string ( bDontUseOriginalWeaponry ) ;
case 'bDisableCustomTrader' :
return string ( bDisableCustomTrader ) ;
case 'bAllowStandartPistolUpgrade' :
return string ( bAllowStandartPistolUpgrade ) ;
case 'bDLCWeaponsForFree' :
return string ( bDLCWeaponsForFree ) ;
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 ] ) ;
}
}
final function UpdateArray ( out array < string > Ar , int Index , const out string Value )
{
if ( Value == "#DELETE" )
Ar . Remove ( Index , 1 ) ;
else
{
if ( Index >= Ar . Length )
Ar . Length = Index + 1 ;
Ar [ Index ] = Value ;
}
}
function WebAdminSetValue ( name PropName , int ElementIndex , string Value )
{
switch ( PropName )
{
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 ;
2020-06-23 20:38:04 +00:00
case 'bDontUseOriginalWeaponry' :
bDontUseOriginalWeaponry = bool ( Value ) ; break ;
case 'bDisableCustomTrader' :
bDisableCustomTrader = bool ( Value ) ; break ;
case 'bAllowStandartPistolUpgrade' :
bAllowStandartPistolUpgrade = bool ( Value ) ; break ;
case 'bDLCWeaponsForFree' :
bDLCWeaponsForFree = 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 ;
default :
return ;
}
SaveConfig ( ) ;
}
defaultproperties
{
2020-06-23 21:55:48 +00:00
// Main devs
DevList . Add ( "0x0110000100E8984E" ) // Marco
DevList . Add ( "0x01100001023DF8A8" ) // ForrestMarkX
// Some fixes and changes
DevList . Add ( "0x011000010AF1C7CA" ) // inklesspen
DevList . Add ( "0x011000010276FBCB" ) // GenZmeY
2020-06-23 20:38:04 +00:00
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 = 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 ) )
2020-06-23 20:38:04 +00:00
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 = "bDLCWeaponsForFree" , UIName = "Free DLC weapons" , UIDesc = "Allows to buy DLC 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
}