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 ] ;
} ;
2020-07-07 17:01:17 +00:00
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 ;
2022-09-16 02:50:42 +00:00
var config array < string > PerkClasses , CustomChars , AdminCommands , BonusGameSongs , BonusGameFX ;
2020-07-07 17:01:17 +00:00
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 ;
2021-02-08 19:42:19 +00:00
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 ;
2021-02-08 19:42:19 +00:00
var config bool bKillMessages , bDamageMessages , bEnableMapVote , bNoAdminCommands , bNoWebAdmin , bNoBoomstickJumping , bDumpXMLStats , bRagdollFromFall , bRagdollFromMomentum , bRagdollFromBackhit , bAddCountryTags , bThrowAllWeaponsOnDeath ;
2017-10-20 02:00:49 +00:00
2022-05-18 05:56:26 +00:00
var KFGI _Access KFGIA ;
2020-07-07 17:01:17 +00:00
//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 ) ;
2023-05-14 02:49:12 +00:00
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.
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
//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 ;
}
2023-05-14 02:49:12 +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' ;
2023-05-14 02:49:12 +00:00
2022-05-18 05:56:26 +00:00
KFGIA = new ( KFGameInfo ( WorldInfo . Game ) ) class 'KFGI_Access' ;
2017-10-20 02:00:49 +00:00
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-06-23 20:38:04 +00:00
2021-02-08 19:42:19 +00:00
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 ;
}
}
}
}
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
// 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' ) ;
2020-06-23 12:48:24 +00:00
2020-07-07 17:49:25 +00:00
UpdateCustomZedXPArray ( ) ;
2020-07-06 16:28:35 +00:00
// Causes bugs
// SetTimer(0.1,'CheckPickupFactories')
2020-06-23 12:48:24 +00:00
}
2020-07-07 17:01:17 +00:00
function UpdateCustomZedXPArray ( )
{
2020-07-07 17:49:25 +00:00
local int i ;
local CustomZedXPStruct zedxp ;
2020-07-07 17:01:17 +00:00
CustomZedXPArray . Length = 0 ;
// Custom XP for custom zeds
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < CustomZedXP . Length ; i ++ )
2020-07-07 17:01:17 +00:00
{
zedxp . zedclass = class < KFPawn _Monster > ( DynamicLoadObject ( CustomZedXP [ i ] . zed , Class 'Class' ) ) ;
2020-11-28 20:12:58 +00:00
if ( zedxp . zedclass == none )
2020-07-07 17:01:17 +00:00
{
` 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));
}
}
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 ;
2023-05-14 02:49:12 +00:00
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 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 ( )
{
2017-10-20 07:02:53 +00:00
local ExtPlayerController ExtPC ;
2020-07-07 19:59:38 +00:00
local KFProj _RicochetStickBullet KFBolt ;
2023-05-14 02:49:12 +00:00
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 ( ) ;
}
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
if ( ! KF . bTraderIsOpen )
2017-10-20 07:02:53 +00:00
{
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 ) ;
}
}
2020-06-22 04:53:15 +00:00
function bool IsFromMod ( Object O )
{
2020-11-28 19:53:57 +00:00
local string PackageName ;
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
if ( O == None )
2020-11-28 19:53:57 +00:00
return false ;
2023-05-14 02:49:12 +00:00
2020-11-28 19:53:57 +00:00
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 ;
}
2023-05-14 02:49:12 +00:00
2020-11-28 19:53:57 +00:00
return true ;
2020-06-22 04:53:15 +00:00
}
2022-07-12 14:12:33 +00:00
function bool HasModsInDamageInfo ( DamageInfo DI )
{
local class < Actor > DamageCauser ;
local class < KFDamageType > DamageType ;
2023-05-14 02:49:12 +00:00
2022-07-12 14:12:33 +00:00
foreach DI . DamageCausers ( DamageCauser )
if ( IsFromMod ( DamageCauser ) )
return true ;
2023-05-14 02:49:12 +00:00
2022-07-12 14:12:33 +00:00
foreach DI . DamageTypes ( DamageType )
if ( IsFromMod ( DamageType ) )
return true ;
2023-05-14 02:49:12 +00:00
2022-07-12 14:12:33 +00:00
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 ;
2020-06-22 04:53:15 +00:00
local KFPawn _Monster KFM ;
2022-07-12 14:12:33 +00:00
local int i ;
2020-11-28 19:53:57 +00:00
local KFPlayerReplicationInfo DamagerKFPRI ;
local float XP ;
local KFPerk InstigatorPerk ;
2022-07-12 14:12:33 +00:00
local DamageInfo DamageInfo ;
local class < KFPerk > DamagePerk ;
2023-05-14 02:49:12 +00:00
2020-06-22 04:53:15 +00:00
KFM = KFPawn _Monster ( Killed . Pawn ) ;
2022-07-12 14:12:33 +00:00
foreach KFM . DamageHistory ( DamageInfo )
2017-10-20 02:00:49 +00:00
{
2022-07-12 14:12:33 +00:00
DamagerKFPRI = KFPlayerReplicationInfo ( DamageInfo . DamagerPRI ) ;
if ( DamagerKFPRI == None ) continue ;
2023-05-14 02:49:12 +00:00
2022-07-12 14:12:33 +00:00
// if no mods - exit the loop, the game will add experience by itself
2023-05-14 02:49:12 +00:00
if ( ! HasModsInDamageInfo ( DamageInfo ) && ! KFGIA . IsCustomZed ( KFM . class ) ) continue ;
2022-07-12 14:12:33 +00:00
KFPC = KFPlayerController ( DamagerKFPRI . Owner ) ;
if ( KFPC == None ) continue ;
2023-05-14 02:49:12 +00:00
2022-07-12 14:12:33 +00:00
i = CustomZedXPArray . Find ( 'zedclass' , KFM . Class ) ;
if ( i != INDEX _NONE )
2020-11-28 19:53:57 +00:00
{
2022-07-12 14:12:33 +00:00
XP = CustomZedXPArray [ i ] . XPValues [ MyKFGI . GameDifficulty ] ;
}
else
{
XP = KFM . static . GetXPValue ( MyKFGI . GameDifficulty ) ;
}
2023-05-14 02:49:12 +00:00
2022-07-12 14:12:33 +00:00
InstigatorPerk = KFPC . GetPerk ( ) ;
2023-05-14 02:49:12 +00:00
2022-07-12 14:12:33 +00:00
// 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 ;
}
2023-05-14 02:49:12 +00:00
2022-07-12 14:12:33 +00:00
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 )
{
2022-07-12 14:27:51 +00:00
local KFPlayerController KFPC ;
local ExtPlayerController ExtPC ;
local ExtPerkManager KillersPerk ;
local KFPawn _Monster KFPM ;
2023-05-14 02:49:12 +00:00
2020-11-28 22:51:29 +00:00
if ( bRespawnCheck && Killed . bIsPlayer )
CheckRespawn ( Killed ) ;
2023-05-14 02:49:12 +00:00
2022-07-12 14:27:51 +00:00
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
{
2022-07-12 14:27:51 +00:00
ExtPC = ExtPlayerController ( Killer ) ;
if ( ExtPC != None && ExtPC . ActivePerkManager != None )
ExtPC . ActivePerkManager . PlayerKilled ( KFPM , LastKillDamageType ) ;
2023-05-14 02:49:12 +00:00
2022-07-12 14:27:51 +00:00
if ( bKillMessages && Killer . PlayerReplicationInfo != None )
BroadcastKillMessage ( Killed . Pawn , Killer ) ;
2023-05-14 02:49:12 +00:00
2020-11-28 22:51:29 +00:00
CustomXP ( Killer , Killed ) ;
}
2023-05-14 02:49:12 +00:00
2022-07-12 14:27:51 +00:00
if ( MyKFGI != None && MyKFGI . IsZedTimeActive ( ) && KFPM != None )
2017-10-20 07:02:53 +00:00
{
KFPC = KFPlayerController ( Killer ) ;
2022-07-12 14:27:51 +00:00
if ( KFPC != None )
2017-10-20 07:02:53 +00:00
{
KillersPerk = ExtPerkManager ( KFPC . GetPerk ( ) ) ;
2022-07-12 14:27:51 +00:00
if ( MyKFGI . ZedTimeRemaining > 0. f && KillersPerk != None && KillersPerk . GetZedTimeExtensions ( KFPC . GetLevel ( ) ) > MyKFGI . ZedTimeExtensionsUsed )
2017-10-20 07:02:53 +00:00
{
MyKFGI . DramaticEvent ( 1.0 ) ;
MyKFGI . ZedTimeExtensionsUsed ++ ;
}
}
}
2023-05-14 02:49:12 +00:00
2022-07-12 14:27:51 +00:00
ExtPC = ExtPlayerController ( Killed ) ;
if ( ExtPC != None )
CheckPerkChange ( ExtPC ) ;
2023-05-14 02:49:12 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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.
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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
2020-06-22 04:53:15 +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 ;
2023-05-14 02:49:12 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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
{
2017-10-20 07:02:53 +00:00
LastDamageDealer = ExtPlayerController ( InstigatedBy ) ;
2020-11-28 20:12:58 +00:00
if ( bDamageMessages && LastDamageDealer != None && ! LastDamageDealer . bNoDamageTracking )
2017-10-20 07:02:53 +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' ) ;
}
else
{
LastDamageDealer = None ;
// Give credits to pet's owner.
2020-11-28 20:12:58 +00:00
if ( Ext _T _MonsterPRI ( InstigatedBy . PlayerReplicationInfo ) != None )
2017-10-20 07:02:53 +00:00
HackSetHistory ( KFPawn ( Injured ) , Injured , Ext _T _MonsterPRI ( InstigatedBy . PlayerReplicationInfo ) . OwnerController , Damage , HitLocation ) ;
}
2017-10-20 02:00:49 +00:00
}
2022-07-12 14:34:14 +00:00
else if ( InstigatedBy . Pawn != None && 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
}
}
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 ( 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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ) ;
2023-05-14 02:49:12 +00:00
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 ;
}
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
// Actually save.
ServerStatLoader . FlushData ( ) ;
PC . ActivePerkManager . SaveData ( ServerStatLoader ) ;
ServerStatLoader . SaveStatFile ( PC ) ;
PC . ActivePerkManager . bStatsDirty = false ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
// 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 ;
2023-05-14 02:49:12 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ;
2021-02-08 19:42:19 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ;
2023-05-14 02:49:12 +00:00
local LocalPlayer LP ;
2017-10-20 02:00:49 +00:00
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 )
{
2023-05-14 02:49:12 +00:00
LP = LocalPlayer ( KFPC . Player ) ;
if ( LP != None )
{
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 ( ) ;
}
2023-05-14 02:49:12 +00:00
}
2017-10-20 02:00:49 +00:00
}
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 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 ) ;
}
2020-11-28 20:12:58 +00:00
else if ( PC . bSetPerk )
2017-10-20 07:02:53 +00:00
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 ;
}
}
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 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 ;
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 07:02:53 +00:00
function Tick ( float DeltaTime )
{
local bool bCheckedWave ;
local ExtPlayerController ExtPC ;
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
if ( KFGameReplicationInfo ( WorldInfo . GRI ) . bTraderIsOpen && ! bCheckedWave )
2017-10-20 07:02:53 +00:00
{
foreach WorldInfo . AllControllers ( class 'ExtPlayerController' , ExtPC )
CheckPerkChange ( ExtPC ) ;
2023-05-14 02:49:12 +00:00
2017-10-20 07:02:53 +00:00
bCheckedWave = true ;
}
2020-11-28 20:12:58 +00:00
else if ( bCheckedWave )
2017-10-20 07:02:53 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
// 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 ;
}
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ;
2023-05-14 02:49:12 +00:00
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 ;
}
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
// 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 ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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
{
2022-09-16 03:36:06 +00:00
return WorldInfo . NetMode == NM _StandAlone || ( P != None && P . ShowAdminName ( ) && ( P . AdminType <= AT _Admin || P . AdminType == AT _Player ) ) ;
2017-10-20 02:00:49 +00:00
}
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 ;
2023-05-14 02:49:12 +00:00
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 ;
}
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 ;
2023-05-14 02:49:12 +00:00
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 ;
}
2023-05-14 02:49:12 +00:00
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' ) ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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' ) ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
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 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 '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 '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 ] ) ;
2021-02-08 19:42:19 +00:00
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 '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 'BonusGameSongs' :
UpdateArray ( BonusGameSongs , ElementIndex , Value ) ; break ;
case 'BonusGameFX' :
UpdateArray ( BonusGameFX , ElementIndex , Value ) ; break ;
2021-02-08 19:42:19 +00:00
case 'bThrowAllWeaponsOnDeath' :
bThrowAllWeaponsOnDeath = bool ( Value ) ; break ;
2017-10-20 02:00:49 +00:00
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" ) )
2021-02-08 19:42:19 +00:00
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 ) )
2017-10-21 16:12:14 +00:00
}