1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFGameInfo_WeeklySurvival.uc
2022-09-01 18:58:51 +03:00

1510 lines
46 KiB
Ucode

//=============================================================================
// KFGameInfo_WeeklySurvival
//=============================================================================
// Weekly variant of survival with runtime adjusted rule sets.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2017 Tripwire Interactive LLC
// - Dan Weiss
//=============================================================================
class KFGameInfo_WeeklySurvival extends KFGameInfo_Survival;
/** Current frame booms */
var int CurrentFrameBooms;
/** Index of event to use as the default block */
var int ActiveEventIdx;
//-----------------------------------------------------------------------------
// Statics
static event class<GameInfo> SetGameType(string MapName, string Options, string Portal)
{
local KFGameEngine KGE;
KGE = KFGameEngine(class'Engine'.static.GetEngine());
if (KGE != none)
{
//Valid index
if (KGE.GetWeeklyEventIndex() >= 0)
{
return super.SetGameType(MapName, Options, Portal);
}
}
//Invalid state, set to normal survival
return class'KFGameInfo_Survival';
}
static function bool GametypeChecksDifficulty()
{
return false;
}
static function bool GametypeChecksWaveLength()
{
return false;
}
//-----------------------------------------------------------------------------
// Initialization
event InitGame( string Options, out string ErrorMessage )
{
Super.InitGame(Options, ErrorMessage);
//SetModifiedGameDifficulty();
SetPickupItemList();
SetZedTimeOverrides();
SetSpawnPointOverrides();
OutbreakEvent.SetWorldInfoOverrides();
}
event PreBeginPlay()
{
super.PreBeginPlay();
OutbreakEvent.UpdateGRI();
if (Role == Role_Authority && MyKFGRI != none)
{
MyKFGRI.NotifyWeeklyEventIndex(ActiveEventIdx);
if ( OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups)
{
MyKFGRI.NotifyBrokenTrader();
}
}
}
event PostBeginPlay()
{
super.PostBeginPlay();
if (OutbreakEvent.ActiveEvent.TimeBetweenWaves >= 0.f)
{
TimeBetweenWaves = OutbreakEvent.ActiveEvent.TimeBetweenWaves;
}
}
function CreateOutbreakEvent()
{
//The KFGameEngine at startup will store the week index of our current time
// Pull from there and figure out which event it corresponds to.
// The beginning of time to reset the loop can be changed in UKFGameEngine::UpdateTimedGameEvents
local KFGameEngine KGE;
super.CreateOutbreakEvent();
KGE = KFGameEngine(class'Engine'.static.GetEngine());
if (KGE != none)
{
ActiveEventIdx = KGE.GetWeeklyEventIndex() % OutbreakEvent.SetEvents.Length;
}
ActiveEventIdx = OutbreakEvent.SetActiveEvent(ActiveEventIdx);
}
function bool UsesModifiedDifficulty()
{
return true;
}
function SetModifiedGameDifficulty()
{
super.SetModifiedGameDifficulty();
if (OutbreakEvent == none)
{
CreateOutbreakEvent();
}
//Set game difficulty. super will create the intended DifficultyInfo object.
MinGameDifficulty = OutbreakEvent.ActiveEvent.EventDifficulty;
MaxGameDifficulty = OutbreakEvent.ActiveEvent.EventDifficulty;
GameDifficulty = Clamp(GameDifficulty, MinGameDifficulty, MaxGameDifficulty);
}
//for difficulty override
function bool UsesModifiedLength()
{
return true;
}
function SetModifiedGameLength()
{
GameLength = OutbreakEvent.ActiveEvent.GameLength;
}
/** Allow for updates to various game systems if we have an override allowable item list */
function SetPickupItemList()
{
local STraderItem TraderItem;
local KFPickupFactory_Item ItemFactory;
local int Idx;
if (MyKFGRI.IsGunGameMode())
{
foreach AllActors(class'KFPickupFactory_Item', ItemFactory)
{
for (Idx = ItemFactory.ItemPickups.Length - 1; Idx >= 0; --Idx)
{
if (ItemFactory.ItemPickups[Idx].ItemClass.Name != 'KFInventory_Armor')
{
ItemFactory.ItemPickups.Remove(Idx, 1);
}
}
}
return;
}
//If we have an override weapon list, it's not enough to block trader and default inventory.
// Iterate through the item pickups in the map to trim their lists as well.
if (OutbreakEvent.ActiveEvent.TraderWeaponList != none)
{
//So many loops
foreach AllActors(class'KFPickupFactory_Item', ItemFactory)
{
//we dont want item pickups, so kiss them goodbye
if(OutbreakEvent.ActiveEvent.OverrideItemPickupModifier == 0)
{
ItemFactory.ShutDown();
ItemFactory.ItemPickups.Remove(0, ItemFactory.ItemPickups.Length);
continue;
}
foreach OutbreakEvent.ActiveEvent.TraderWeaponList.SaleItems(TraderItem)
{
for (Idx = ItemFactory.ItemPickups.Length - 1; Idx >= 0; --Idx)
{
if (ItemFactory.ItemPickups[Idx].ItemClass.Name != TraderItem.ClassName)
{
ItemFactory.ItemPickups.Remove(Idx, 1);
}
}
}
}
}
}
function SetZedTimeOverrides()
{
if (ZedTimeSlomoScale != OutbreakEvent.ActiveEvent.OverrideZedTimeSlomoScale)
{
ZedTimeSlomoScale = OutbreakEvent.ActiveEvent.OverrideZedTimeSlomoScale;
}
}
function SetSpawnPointOverrides()
{
local KFSpawnVolume KFSV;
foreach WorldInfo.AllActors(class'KFSpawnVolume', KFSV)
{
if (OutbreakEvent.ActiveEvent.OverrideSpawnDerateTime >= 0.f)
{
KFSV.SpawnDerateTime = OutbreakEvent.ActiveEvent.OverrideSpawnDerateTime;
}
if (OutbreakEvent.ActiveEvent.OverrideTeleportDerateTime >= 0.f)
{
KFSV.TeleportDerateTime = OutbreakEvent.ActiveEvent.OverrideTeleportDerateTime;
}
}
}
/** Enable some hax to permanently be in zed time */
function SetPermanentZedTime()
{
local KFPlayerController KFPC;
if (OutbreakEvent.ActiveEvent.bPermanentZedTime)
{
ZedTimeRemaining = 999999.f;
bZedTimeBlendingOut = false;
LastZedTimeEvent = WorldInfo.TimeSeconds;
SetZedTimeDilation(ZedTimeSlomoScale);
foreach WorldInfo.AllControllers(class'KFPlayerController', KFPC)
{
if (KFPC != none)
{
KFPC.EnterZedTime();
}
}
}
}
//Do a reset on the permanent zed time. Leaves us in zed time, but puts valid players into the partial mode.
function ResetPermanentZed()
{
local KFPlayerController KFPC;
local KFPawn KFP;
foreach WorldInfo.AllControllers(class'KFPlayerController', KFPC)
{
KFP = KFPawn(KFPC.Pawn);
if (KFPC != none && KFP != none)
{
KFP.bUnaffectedByZedTime = !KFPC.IsAffectedByZedTime();
if (KFP.bUnaffectedByZedTime)
{
KFPC.StartPartialZedTimeSightCounter();
}
KFPC.ClientEnterZedTime(KFP.bUnaffectedByZedTime);
}
}
}
function float GetAdjustedAIDoshValue( class<KFPawn_Monster> MonsterClass )
{
if (!OutbreakEvent.ActiveEvent.bBossRushMode)
{
return super.GetAdjustedAIDoshValue(MonsterClass) * OutbreakEvent.ActiveEvent.DoshOnKillGlobalModifier;
}
else
{
if ((WaveNum-1) < OutbreakEvent.ActiveEvent.BossRushOverrideParams.PerWaves.length)
{
return super.GetAdjustedAIDoshValue(MonsterClass) * OutbreakEvent.ActiveEvent.BossRushOverrideParams.PerWaves[WaveNum-1].DoshOnKillGlobalModifier;
}
}
return super.GetAdjustedAIDoshValue(MonsterClass);
}
protected function ScoreMonsterKill( Controller Killer, Controller Monster, KFPawn_Monster MonsterPawn )
{
super.ScoreMonsterKill(Killer, Monster, MonsterPawn);
if(OutbreakEvent.ActiveEvent.bHealAfterKill)
{
if( MonsterPawn != none && MonsterPawn.DamageHistory.Length > 0 )
{
if(OutbreakEvent.ActiveEvent.bHealWithHeadshot)
{
if (MonsterPawn.LastHitZoneIndex == HZI_HEAD)
{
HealAfterKilling( MonsterPawn, Killer, false );
}
}
else
{
HealAfterKilling( MonsterPawn, Killer );
}
}
}
if (OutbreakEvent.ActiveEvent.bGunGameMode)
{
GunGameScoreAssistanceAfterKilling(MonsterPawn, Killer);
}
}
/** Heal players after a Zed was killed, based in more heal to the player that was the killer and less heal to the players that damaged the Zed */
function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer, optional bool bGivePowerUp = true)
{
local int i;
local int j;
local KFPlayerController KFPC;
local KFPlayerReplicationInfo DamagerKFPRI;
local array<DamageInfo> DamageHistory;
local array<KFPlayerController> Attackers;
local KFPawn_Human PawnHuman;
local KFGameInfo KFGI;
DamageHistory = MonsterPawn.DamageHistory;
KFGI = KFGameInfo(WorldInfo.Game);
for ( i = 0; i < DamageHistory.Length; i++ )
{
if( DamageHistory[i].DamagerController != none
&& DamageHistory[i].DamagerController.bIsPlayer
&& DamageHistory[i].DamagerPRI.GetTeamNum() == 0
&& DamageHistory[i].DamagerPRI != none )
{
DamagerKFPRI = KFPlayerReplicationInfo(DamageHistory[i].DamagerPRI);
if( DamagerKFPRI != none )
{
KFPC = KFPlayerController(DamagerKFPRI.Owner);
if( KFPC != none )
{
if(Attackers.Find(KFPC) < 0)
{
PawnHuman = KFPawn_Human(KFPC.Pawn);
Attackers.AddItem(KFPC);
/*
Weekly event Aracnophobia (10):
2 kind of heales: one for killing and another for killing by jumping on enemies.
HealByAssistance is used for the latest, no need to add extra variables.
*/
if( KFPC == Killer && KFGI != none && KFGI.OutbreakEvent.ActiveEvent.bGoompaJumpEnabled )
{
for (j = 0; j < DamageHistory[i].DamageTypes.Length; j++)
{
if (DamageHistory[i].DamageTypes[j] == class 'KFDT_GoompaStomp')
{
PawnHuman.HealDamageForce(MonsterPawn.HealByAssistance, KFPC, class'KFDT_Healing', false, false );
return;
}
}
PawnHuman.HealDamageForce(MonsterPawn.HealByKill, KFPC, class'KFDT_Healing', false, false );
return;
}
//
if( KFPC == Killer )
{
PawnHuman.HealDamageForce(MonsterPawn.HealByKill, KFPC, class'KFDT_Healing', false, false );
if( bGivePowerUp && ( KFPawn_ZedFleshpound(MonsterPawn) != none || KFPawn_ZedScrake(MonsterPawn) != none ))
{
KFPC.ReceivePowerUp(class'KFPowerUp_HellishRage_NoCostHeal');
}
}
else
{
PawnHuman.HealDamageForce(MonsterPawn.HealByAssistance, KFPC, class'KFDT_Healing', false, false );
}
}
}
}
}
}
}
function GunGameScoreAssistanceAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
{
local int i;
local KFPlayerController_WeeklySurvival KFPC_WS;
local array<DamageInfo> DamageHistory;
local KFPlayerReplicationInfo DamagerKFPRI;
local array<KFPlayerController> Attackers;
DamageHistory = MonsterPawn.DamageHistory;
for (i = 0; i < DamageHistory.Length; i++)
{
if (DamageHistory[i].DamagerController != none
&& DamageHistory[i].DamagerController.bIsPlayer
&& DamageHistory[i].DamagerPRI.GetTeamNum() == 0
&& DamageHistory[i].DamagerPRI != none)
{
DamagerKFPRI = KFPlayerReplicationInfo(DamageHistory[i].DamagerPRI);
if (DamagerKFPRI != none)
{
KFPC_WS = KFPlayerController_WeeklySurvival(DamagerKFPRI.Owner);
if (KFPC_WS != none && KFPC_WS != Killer)
{
if (Attackers.Find(KFPC_WS) < 0)
{
Attackers.AddItem(KFPC_WS);
if (KFPC_WS.Pawn.Health > 0)
{
KFPC_WS.GunGameData.Score += MonsterPawn.GunGameAssistanceScore;
UpdateGunGameLevel(KFPC_WS);
}
}
}
}
}
}
}
function StartMatch()
{
super.StartMatch();
if (OutbreakEvent.ActiveEvent.bForceWWLMusic)
{
ForceWWLMusicTrack();
}
}
function CreateDifficultyInfo(string Options)
{
super.CreateDifficultyInfo(Options);
//If we want to use custom weapon respawn times, set them here
if (OutbreakEvent.ActiveEvent.bUseOverrideItemRespawnTime)
{
DifficultyInfo.NumPlayers_WeaponPickupRespawnTime = OutbreakEvent.ActiveEvent.OverrideItemRespawnTime;
}
//If we want to use custom ammo respawn times, set them here
if (OutbreakEvent.ActiveEvent.bUseOverrideAmmoRespawnTime)
{
DifficultyInfo.NumPlayers_AmmoPickupRespawnTime = OutbreakEvent.ActiveEvent.OverrideAmmoRespawnTime;
}
}
event PostLogin( PlayerController NewPlayer )
{
local KFPlayerController_WeeklySurvival KFPC_WS;
local KFPawn_Customization KFCustomizePawn;
super.PostLogin(NewPlayer);
KFPC_WS = KFPlayerController_WeeklySurvival(NewPlayer);
if (KFPC_WS != none)
{
KFPC_WS.bUsingPermanentZedTime = OutbreakEvent.ActiveEvent.bPermanentZedTime;
KFPC_WS.ZedTimeRadius = OutbreakEvent.ActiveEvent.ZedTimeRadius * OutbreakEvent.ActiveEvent.ZedTimeRadius;
KFPC_WS.ZedTimeBossRadius = OutbreakEvent.ActiveEvent.ZedTimeBossRadius * OutbreakEvent.ActiveEvent.ZedTimeBossRadius;
KFPC_WS.ZedTimeHeight = OutbreakEvent.ActiveEvent.ZedTimeHeight;
KFPC_WS.ZedRecheckTime = OutbreakEvent.ActiveEvent.PermanentZedResetTime;
//Handle any visual-related things for customization pawn so the pregame lobby has the fun things
KFCustomizePawn = KFPawn_Customization(KFPC_WS.Pawn);
if (KFCustomizePawn != none)
{
KFCustomizePawn.IntendedHeadScale = OutbreakEvent.ActiveEvent.PlayerSpawnHeadScale;
KFCustomizePawn.SetHeadScale(KFCustomizePawn.IntendedHeadScale, KFCustomizePawn.CurrentHeadScale);
}
}
LoadGunGameWeapons(NewPlayer);
}
function SetBossIndex()
{
local BossSpawnReplacement Replacement;
local int ReplaceIdx;
local int i;
// Ignore normal events.
if (OutbreakEvent.ActiveEvent.bBossRushMode)
{
if (BossRushEnemies.length == 0)
{
for(i=0; i < default.AIBossClassList.length; ++i)
{
BossRushEnemies.AddItem(i);
}
}
}
BossIndex = Rand(default.AIBossClassList.Length);
//Search in the replacement list for the one that the game type wanted to use
// If we find it, grab the appropriate index into the original AI class list
// so we can properly cache it.
foreach OutbreakEvent.ActiveEvent.BossSpawnReplacementList(Replacement)
{
if (Replacement.SpawnEntry == BossIndex)
{
ReplaceIdx = AIBossClassList.Find(Replacement.NewClass);
if (ReplaceIdx != INDEX_NONE)
{
BossIndex = ReplaceIdx;
break;
}
}
}
MyKFGRI.CacheSelectedBoss(BossIndex);
}
//-----------------------------------------------------------------------------
// Ticking
function Tick(float DeltaTime)
{
CurrentFrameBooms = 0;
super.Tick(DeltaTime);
}
function TickZedTime( float DeltaTime )
{
super.TickZedTime(DeltaTime);
//If we're in permanent mode with a valid wave, set remaining time to a stupid value to stay in zed time
if (OutbreakEvent.ActiveEvent.bPermanentZedTime && IsWaveActive())
{
//Keep up the timer if we have enough zeds left or it's a boss phase
if (MyKFGRI.AIRemaining > OutbreakEvent.ActiveEvent.PermanentZedTimeCutoff || WaveNum == WaveMax)
{
ZedTimeRemaining = 999999.f;
}
//Else start the fade back to normal
else if (ZedTimeRemaining > ZedTimeBlendOutTime)
{
ZedTimeRemaining = ZedTimeBlendOutTime;
ClearZedTimePCTimers();
}
}
}
function WaveEnded(EWaveEndCondition WinCondition)
{
local KFPawn_Human Pawn;
local bool bWasFirstTime;
// This function is called multiple times in a row. Only apply it once.
bWasFirstTime = bWaveStarted;
super.WaveEnded(WinCondition);
if (OutbreakEvent.ActiveEvent.bPermanentZedTime && ZedTimeRemaining > ZedTimeBlendOutTime)
{
ClearZedTimePCTimers();
ZedTimeRemaining = ZedTimeBlendOutTime;
}
if (OutbreakEvent.ActiveEvent.bHealPlayerAfterWave)
{
foreach WorldInfo.AllPawns(class'KFPawn_Human', Pawn)
{
Pawn.Health = Pawn.HealthMax;
}
}
if (WinCondition == WEC_WaveWon && bWasFirstTime)
{
GrantExtraDoshOnWaveWon();
}
DisableGlobalDamage();
}
/** Grant dosh to every player even no matter it's state when a wave is won. */
function GrantExtraDoshOnWaveWon()
{
local KFPlayerController KFPC;
local int ExtraDosh;
//
if (OutbreakEvent.ActiveEvent.bBossRushMode && (WaveNum-1) < OutbreakEvent.ActiveEvent.BossRushOverrideParams.PerWaves.length)
{
ExtraDosh = OutbreakEvent.ActiveEvent.BossRushOverrideParams.PerWaves[WaveNum-1].ExtraDoshGrantedonWaveWon;
foreach WorldInfo.AllControllers(class'KFPlayerController', KFPC)
{
KFPlayerReplicationInfo(KFPC.PlayerReplicationInfo).AddDosh(ExtraDosh, true);
}
}
}
function ClearZedTimePCTimers()
{
local KFPlayerController_WeeklySurvival KFPC;
foreach AllActors(class'KFPlayerController_WeeklySurvival', KFPC)
{
KFPC.ClearTimer('RecheckZedTime');
}
}
//-----------------------------------------------------------------------------
// Completion
function EndOfMatch(bool bVictory)
{
local KFPlayerController KFPC;
if (bVictory)
{
foreach WorldInfo.AllControllers(class'KFPlayerController', KFPC)
{
KFPC.CompletedWeeklySurvival();
}
}
super.EndOfMatch(bVictory);
}
function StartWave()
{
super.StartWave();
// Stop Global Damage for boss wave
if (!OutbreakEvent.ActiveEvent.bApplyGlobalDamageBossWave && WaveNum == WaveMax)
{
DisableGlobalDamage();
}
// In case there was a previous boss wave. Not sure if possible
else if (OutbreakEvent.ActiveEvent.GlobalDamageTickRate > 0.f && OutbreakEvent.ActiveEvent.GlobalDamageTickAmount > 0.f)
{
if(!IsTimerActive('EnableGlobalDamage', self))
{
SetTimer(OutbreakEvent.ActiveEvent.DamageDelayAfterWaveStarted, false, 'EnableGlobalDamage', self);
}
// Check if we are in the zed frustration time to stop applying damage
SetTimer(1.0f, true, 'CheckForZedFrustrationMode', self);
}
if (OutbreakEvent.ActiveEvent.bPermanentZedTime)
{
//If we're a boss wave, wait until the camera animation is going
if (WaveNum == WaveMax)
{
SetTimer(0.25f, true, nameof(BossCameraZedTimeRecheck));
}
else
{
//Enable permanent zed time
SetPermanentZedTime();
}
}
if (OutbreakEvent.ActiveEvent.AdditionalBossWaveInfo != none && WaveNum == WaveMax)
{
SetTimer(OutbreakEvent.ActiveEvent.AdditionalBossWaveStartDelay, true, nameof(SpawnBossWave));
}
if (OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups)
{
OverridePickupList();
}
}
function bool OverridePickupList()
{
local KFPickupFactory PickupFactory;
local KFPickupFactory_Item ItemFactory;
local KFGameReplicationInfo_WeeklySurvival KFGRI_WS;
KFGRI_WS=KFGameReplicationInfo_WeeklySurvival(MyKFGRI);
if (KFGRI_WS == none)
return false;
foreach ItemPickups(PickupFactory)
{
ItemFactory = KFPickupFactory_Item(PickupFactory);
if (ItemFactory == none)
continue;
KFGRI_WS.OverrideWeaponPickups(ItemFactory);
ItemFactory.OverridePickup();
}
return true;
}
function EnableGlobalDamage()
{
MyKFGRI.SetGlobalDamage(true);
SetTimer(OutbreakEvent.ActiveEvent.GlobalDamageTickRate, true, 'ApplyGlobalDamage', OutbreakEvent);
}
function DisableGlobalDamage()
{
MyKFGRI.SetGlobalDamage(false);
if (IsTimerActive('ApplyGlobalDamage', OutbreakEvent))
{
ClearTimer('ApplyGlobalDamage', OutbreakEvent);
}
if (IsTimerActive('EnableGlobalDamage', self))
{
ClearTimer('EnableGlobalDamage', self);
}
}
function CheckForZedFrustrationMode()
{
if(IsTimerActive('ApplyGlobalDamage', OutbreakEvent))
{
if(class'KFAIController'.default.FrustrationThreshold > 0 && MyKFGRI.AIRemaining <= class'KFAIController'.default.FrustrationThreshold)
{
DisableGlobalDamage();
ClearTimer('CheckForZedFrustrationMode', self);
}
}
}
function BossCameraZedTimeRecheck()
{
local KFPawn_Monster KFM;
local KFInterface_MonsterBoss BossRef;
foreach WorldInfo.AllPawns(class'KFPawn_Monster', KFM)
{
if (KFM.static.IsABoss())
{
BossRef = KFInterface_MonsterBoss(KFM);
if (BossRef != none)
{
if (BossRef.UseAnimatedBossCamera())
{
return;
}
//We have a boss that isn't animating. Go ahead and start zed time
else
{
ClearTimer(nameof(BossCameraZedTimeRecheck));
SetPermanentZedTime();
}
}
}
}
}
//Hijack existing boss summon functionality to spawn extra boss wave
function SpawnBossWave()
{
SetTimer(OutbreakEvent.ActiveEvent.AdditionalBossWaveFrequency, false, nameof(SpawnBossWave));
SpawnManager.SummonBossMinions(OutbreakEvent.ActiveEvent.AdditionalBossWaveInfo.Squads, GetAdditionalBossSpawns());
if (!OutbreakEvent.ActiveEvent.bContinuousAdditionalBossWave)
{
//Arbitrary time, but delay a bit for spawns to go through, then cut off additional boss wave spawning til next timer hit
SetTimer(2.f, false, nameof(PauseAdditionalBossWaves));
}
}
function PauseAdditionalBossWaves()
{
SpawnManager.StopSummoningBossMinions();
}
function byte GetAdditionalBossSpawns()
{
return byte(Lerp(OutbreakEvent.ActiveEvent.AdditionalBossSpawnCount.X, OutbreakEvent.ActiveEvent.AdditionalBossSpawnCount.Y,fMax(NumPlayers, 1) / float(MaxPlayers)));
}
function OpenTrader()
{
//If we're in permanent zed time, disable it for trader time
if (OutbreakEvent.ActiveEvent.bPermanentZedTime && ZedTimeRemaining > ZedTimeBlendOutTime)
{
ClearZedTimePCTimers();
ZedTimeRemaining = ZedTimeBlendOutTime;
}
if (!OutbreakEvent.ActiveEvent.bDisableTraders)
{
super.OpenTrader();
}
else if (KFGameReplicationInfo(GameReplicationInfo) != none)
{
KFGameReplicationInfo(GameReplicationInfo).StartScavengeTime(TimeBetweenWaves);
}
}
function SetupNextTrader()
{
if (!OutbreakEvent.ActiveEvent.bDisableTraders)
{
super.SetupNextTrader();
}
}
State TraderOpen
{
function BeginState( Name PreviousStateName )
{
super.BeginState(PreviousStateName);
//Adding the call here. Whether or not super gets called is based on ActiveEvent flag.
ResetAllPickups();
}
}
function InitAllPickups()
{
super.InitAllPickups();
//If this event is trying to do things to the pickup count, redo the init functionality
if (OutbreakEvent.ActiveEvent.OverrideItemPickupModifier >= 0.f || OutbreakEvent.ActiveEvent.OverrideAmmoPickupModifier >= 0.f)
{
NumWeaponPickups = ItemPickups.Length * (OutbreakEvent.ActiveEvent.OverrideItemPickupModifier >= 0.f ? OutbreakEvent.ActiveEvent.OverrideItemPickupModifier : DifficultyInfo.GetItemPickupModifier());
NumAmmoPickups = AmmoPickups.Length * (OutbreakEvent.ActiveEvent.OverrideAmmoPickupModifier >= 0.f ? OutbreakEvent.ActiveEvent.OverrideAmmoPickupModifier : DifficultyInfo.GetAmmoPickupModifier());
`if(`__TW_SDK_)
if( BaseMutator != none )
{
BaseMutator.ModifyPickupFactories();
}
`endif
ResetAllPickups();
}
}
function ResetAllPickups()
{
local bool bCallReset;
bCallReset = false;
switch(OutbreakEvent.ActiveEvent.PickupResetTime)
{
case PRS_Wave:
bCallReset = IsWaveActive();
break;
case PRS_Trader:
bCallReset = !IsWaveActive();
break;
case PRS_WaveAndTrader:
bCallReset = true;
break;
case PRS_Never:
bCallReset = false;
break;
}
if (bCallReset)
{
super.ResetAllPickups();
}
}
function ResetPickups( array<KFPickupFactory> PickupList, int NumPickups )
{
//If we're resetting ammo and in an ammo list, use that modifier
if (OutbreakEvent.ActiveEvent.WaveAmmoPickupModifiers.Length >= WaveMax && KFPickupFactory_Ammo(PickupList[0]) != none)
{
NumPickups *= OutbreakEvent.ActiveEvent.WaveAmmoPickupModifiers[WaveNum];
super(KFGameInfo).ResetPickups(PickupList, NumPickups);
}
//If we're resetting items and in an item list, use that modifier
else if (OutbreakEvent.ActiveEvent.WaveItemPickupModifiers.Length >= WaveMax && KFPickupFactory_Item(PickupList[0]) != none)
{
NumPickups *= OutbreakEvent.ActiveEvent.WaveItemPickupModifiers[WaveNum];
if(OutbreakEvent.ActiveEvent.OverrideItemPickupModifier == 0) NumPickups = 0;
super(KFGameInfo).ResetPickups(PickupList, NumPickups);
}
//Otherwise, use normal path
else
{
super.ResetPickups(PickupList, NumPickups);
}
}
//-----------------------------------------------------------------------------
// Spawning
/** Allow specific game type to override the spawn class. Default implementation returns from the AI class list. */
function class<KFPawn_Monster> GetAISpawnType(EAIType AIType)
{
if (WaveNum < WaveMax || OutbreakEvent.ActiveEvent.bAllowSpawnReplacementDuringBossWave)
{
return OutbreakEvent.GetAISpawnOverrirde(AIType);
}
//No override, return default
return AIClassList[AIType];
}
/** Whether or not a specific primary weapon is allowed. Called at player spawn time while setting inventory. */
function bool AllowPrimaryWeapon(string ClassPath)
{
local STraderItem Item;
if (OutbreakEvent.ActiveEvent.SpawnWeaponList != none)
{
foreach OutbreakEvent.ActiveEvent.SpawnWeaponList.SaleItems(Item)
{
if ( name(Item.WeaponDef.default.WeaponClassPath) == name(ClassPath) )
{
return true;
}
}
return false;
}
return true;
}
/** Whether or not a specific secondary weapon is allowed. Called at player spawn time while setting inventory. */
function bool AllowSecondaryWeapon(string ClassPath)
{
local STraderItem Item;
if (OutbreakEvent.ActiveEvent.SpawnWeaponList != none && OutbreakEvent.ActiveEvent.bSpawnWeaponListAffectsSecondaryWeapons)
{
foreach OutbreakEvent.ActiveEvent.SpawnWeaponList.SaleItems(Item)
{
if ( name(Item.WeaponDef.default.WeaponClassPath) == name(ClassPath) )
{
return true;
}
}
return false;
}
return true;
}
/** Allows gametype to adjust starting grenade count. Called at player spawn time from GiveInitialGrenadeCount in the inventory. */
function int AdjustStartingGrenadeCount(int CurrentCount)
{
if (OutbreakEvent.ActiveEvent.bDisableGrenades)
{
return 0;
}
return CurrentCount;
}
/** Allows gametype to validate a perk for the current match */
function bool IsPerkAllowed(class<KFPerk> PerkClass)
{
Local int index;
if(OutbreakEvent.ActiveEvent.PerksAvailableList.length == 0)
{
return true;
}
for( index=0 ; index<OutbreakEvent.ActiveEvent.PerksAvailableList.length ; index++)
{
if(OutbreakEvent.ActiveEvent.PerksAvailableList[index] == PerkClass)
{
return true;
}
}
return false;
}
function LoadGunGameWeapons(Controller NewPlayer)
{
local int i, RandomNumber;
local KFPlayerController_WeeklySurvival KFPC_WS;
local class<Inventory> InventoryClass;
local Inventory Inv;
local KFWeapon Weapon;
// Deactivated preload in console version
if (OutbreakEvent.ActiveEvent.bGunGameMode && WorldInfo.IsConsoleBuild() == false)
{
KFPC_WS = KFPlayerController_WeeklySurvival(NewPlayer);
if (KFPC_WS == none)
{
return;
}
for (i=0; i < OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameLevels.Length; i++)
{
RandomNumber = Rand(OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameLevels[i].GrantedWeapons.Length);
KFPC_WS.GunGameData.GunGamePreselectedWeapons.AddItem(RandomNumber);
InventoryClass = class<KFWeapon> (DynamicLoadObject(OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameLevels[i].GrantedWeapons[RandomNumber].default.WeaponClassPath, class'Class'));
Inv = KFPC_WS.Pawn.InvManager.CreateInventory(InventoryClass, true);
if (Inv != none)
{
Weapon = KFWeapon(Inv);
if (Weapon != none)
{
Weapon.RemoveGun();
}
}
}
}
}
function RestartPlayer(Controller NewPlayer)
{
local KFPawn_Human KFPH;
super.RestartPlayer(NewPlayer);
KFPH = KFPawn_Human(NewPlayer.Pawn);
OutbreakEvent.AdjustRestartedPlayer(KFPH);
}
function RestartGunGamePlayerWeapon(KFPlayerController_WeeklySurvival KFPC_WS, byte WaveToUse)
{
local byte i;
local int CurrentGunGameWaveLevel;
super.RestartGunGamePlayerWeapon(KFPC_WS, WaveToUse);
ResetGunGame(KFPC_WS);
CurrentGunGameWaveLevel = -1;
// Find wave level, the data needs to be ordered
for (i = 0; i < OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameRespawnLevels.Length; i++)
{
if (WaveToUse >= OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameRespawnLevels[i].Wave)
{
CurrentGunGameWaveLevel = OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameRespawnLevels[i].Level - 1;
}
}
// If any level we force gun game update
if (CurrentGunGameWaveLevel >= 0)
{
KFPC_WS.GunGameData.Score = OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameLevels[CurrentGunGameWaveLevel].RequiredScore;
UpdateGunGameLevel(KFPC_WS);
}
}
function DoDeathExplosion(Pawn DeadPawn, KFGameExplosion ExplosionTemplate, class<KFPawn> ExplosionIgnoreClass)
{
local KFExplosionActorReplicated ExploActor;
if (CurrentFrameBooms < OutbreakEvent.ActiveEvent.MaxBoomsPerFrame)
{
ExploActor = Spawn(class'KFExplosionActorReplicated', DeadPawn, , DeadPawn.Location);
if (ExploActor != none)
{
ExploActor.InstigatorController = DeadPawn.Controller;
ExploActor.Instigator = DeadPawn;
ExploActor.Attachee = DeadPawn;
ExplosionTemplate.ActorClassToIgnoreForDamage = ExplosionIgnoreClass;
ExploActor.Explode(ExplosionTemplate, vect(0, 0, 1));
++CurrentFrameBooms;
}
}
}
simulated function AddWeaponsFromSpawnList(KFPawn P)
{
local STraderItem Item;
if (OutbreakEvent.ActiveEvent.SpawnWeaponList != none || OutbreakEvent.ActiveEvent.bAddSpawnListToLoadout)
{
foreach OutbreakEvent.ActiveEvent.SpawnWeaponList.SaleItems(Item)
{
P.DefaultInventory.AddItem(class<Weapon>(DynamicLoadObject(Item.WeaponDef.default.WeaponClassPath, class'Class')));
}
}
}
simulated function OverrideHumanDefaults(KFPawn_Human P)
{
if (OutbreakEvent.ActiveEvent.JumpZ >= 0.0f)
{
P.JumpZ = OutbreakEvent.ActiveEvent.JumpZ;
}
}
simulated function ModifyDamageGiven(out int InDamage, optional Actor DamageCauser, optional KFPawn_Monster MyKFPM, optional KFPlayerController DamageInstigator, optional class<KFDamageType> DamageType, optional int HitZoneIdx )
{
local KFPlayerController_WeeklySurvival KFPC;
local int Streak;
if (OutbreakEvent.ActiveEvent.bGoompaJumpEnabled)
{
KFPC = KFPlayerController_WeeklySurvival(DamageInstigator);
if (KFPC != none)
{
Streak = KFPC.GoompaStreakBonus < KFPC.MaxGoompaStreak ? KFPC.GoompaStreakBonus : KFPC.MaxGoompaStreak;
InDamage *= (1 + OutbreakEvent.ActiveEvent.GoompaStreakDamage * Streak);
}
}
}
/*
* Gun Game
*/
function ResetGunGame(KFPlayerController_WeeklySurvival KFPC_WS)
{
KFPC_WS.GunGameData.Score = 0;
KFPC_WS.GunGameData.Level = 0;
KFPC_WS.UpdateGunGameWidget(0, OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameLevels[0].RequiredScore, 0, OutbreakEvent.ActiveEvent.GunGamePerksData.GunGameLevels.Length);
}
function NotifyKilled(Controller Killer, Controller Killed, Pawn KilledPawn, class<DamageType> damageType )
{
local KFPawn_Monster KFPM;
local KFPlayerController_WeeklySurvival KFPC_WS_Killer, KFPC_WS_Killed;
super.NotifyKilled(Killer, Killed, KilledPawn, damageType);
KFPM = KFPawn_Monster(KilledPawn);
KFPC_WS_Killer = KFPlayerController_WeeklySurvival(Killer);
KFPC_WS_Killed = KFPlayerController_WeeklySurvival(Killed);
if (OutbreakEvent.ActiveEvent.bGunGameMode)
{
// If pawn is monster increase gun game score for that monster
if (KFPM != none && KFPC_WS_Killer != none)
{
if (KFPC_WS_Killer.Pawn.Health > 0)
{
KFPC_WS_Killer.GunGameData.Score += KFPM.GunGameKilledScore;
UpdateGunGameLevel(KFPC_WS_Killer);
}
}
else
{
// If pawn is human reset game score (we can just check Killed exists as Controller
if (KFPC_WS_Killed != none)
{
ResetGunGame(KFPC_WS_Killed);
}
}
}
if (OutbreakEvent.ActiveEvent.bVIPGameMode)
{
if (KFPC_WS_Killed != none && KFPC_WS_Killed.VIPGameData.isVIP)
{
// UnregisterPlayer is done on the same frame but this function comes first..
// we queue a petition to end the game if no vip is found
SetTimer(1.5f, false, 'OnVIPDiesEndMatch');
}
}
}
function GunGameLevelGrantWeapon(KFPlayerController_WeeklySurvival KFPC_WS, class<KFWeaponDefinition> ToGrantWeaponDefinition)
{
local class<Inventory> InventoryClass;
local Inventory Inv;
local KFWeapon KFW;
InventoryClass = class<KFWeapon> (DynamicLoadObject(ToGrantWeaponDefinition.default.WeaponClassPath, class'Class'));
Inv = KFPC_WS.Pawn.InvManager.CreateInventory(InventoryClass, true);
if (Inv != none)
{
KFW = KFWeapon(Inv);
if (KFW != none)
{
KFW.bDropOnDeath = false;
KFW.bGivenAtStart = true;
KFW = KFInventoryManager(KFPC_WS.Pawn.InvManager).CombineWeaponsOnPickup( KFW );
KFW.NotifyPickedUp();
// Refill ammo
KFW.AmmoCount[0] = KFW.MagazineCapacity[0];
KFW.AddAmmo(KFW.GetMaxAmmoAmount(0));
KFW.AmmoCount[1] = KFW.MagazineCapacity[1];
KFW.AddSecondaryAmmo(KFW.GetMaxAmmoAmount(1));
KFPC_WS.Pawn.InvManager.SetCurrentWeapon(KFW);
}
}
}
function UpdateGunGameLevel(KFPlayerController_WeeklySurvival KFPC_WS)
{
local byte CurrentLevel, InitialLevel, RandomNumber;
local class<KFWeaponDefinition> ToGrantWeaponDefinition;
local GunGamePerkData PerkData;
local KFWeapon CurrentWeapon;
local bool found_base_weapon;
if (!OutbreakEvent.ActiveEvent.bGunGameMode)
return;
PerkData = OutbreakEvent.ActiveEvent.GunGamePerksData;
InitialLevel = KFPC_WS.GunGameData.Level;
CurrentLevel = KFPC_WS.GunGameData.Level;
// Update to the current level
while (CurrentLevel < PerkData.GunGameLevels.Length && KFPC_WS.GunGameData.Score >= PerkData.GunGameLevels[CurrentLevel].RequiredScore)
{
++CurrentLevel;
}
// Update HUD
if (CurrentLevel > PerkData.GunGameLevels.Length - 1)
{
KFPC_WS.UpdateGunGameWidget(KFPC_WS.GunGameData.Score, -1, PerkData.GunGameLevels.Length, PerkData.GunGameLevels.Length);
}
else
{
KFPC_WS.UpdateGunGameWidget(KFPC_WS.GunGameData.Score, PerkData.GunGameLevels[CurrentLevel].RequiredScore, CurrentLevel, PerkData.GunGameLevels.Length);
}
if (InitialLevel != CurrentLevel)
{
// If this player reached last level..
if (CurrentLevel > PerkData.GunGameLevels.Length - 1)
{
if (bGunGamePlayerOnLastGun == false)
{
KFPC_WS.GunGameData.GiveWeaponMaster = true;
}
bGunGamePlayerOnLastGun = true;
KFPC_WS.PlayGunGameMessage(true);
}
else
{
KFPC_WS.PlayGunGameMessage(false);
}
KFPC_WS.GunGameData.Level = CurrentLevel;
found_base_weapon = false;
// Remove Previous Granted Items
foreach KFPC_WS.Pawn.InvManager.InventoryActors ( class'KFWeapon', CurrentWeapon )
{
// (not if it's knife/9mm/syringe)
if (!class'KFPerk'.static.IsKnife(CurrentWeapon)
&& !class'KFPerk_SWAT'.static.Is9mm(CurrentWeapon)
&& !class'KFPerk'.static.IsSyringe(CurrentWeapon)
&& !class'KFPerk'.static.IsWelder(CurrentWeapon))
{
// To prevent audio/vfx lock, while firing when removing the equipped weapon we do a proper gun remove
// This new function manages it's state internally
CurrentWeapon.RemoveGun();
}
if (class'KFPerk_SWAT'.static.Is9mm(CurrentWeapon))
{
found_base_weapon = true;
}
}
// We need to grant 9MM is we don't have it and we jumped levels
if (CurrentLevel > 1 && found_base_weapon == false)
{
ToGrantWeaponDefinition = PerkData.GunGameLevels[0].GrantedWeapons[0];
GunGameLevelGrantWeapon(KFPC_WS, ToGrantWeaponDefinition);
}
// Grant Weapon
// Generate random weapon to grant from the list
// Deactivated preload in console version
if (WorldInfo.IsConsoleBuild())
{
RandomNumber = Rand(PerkData.GunGameLevels[CurrentLevel-1].GrantedWeapons.Length);
}
else
{
RandomNumber = KFPC_WS.GunGameData.GunGamePreselectedWeapons[CurrentLevel-1];
}
ToGrantWeaponDefinition = PerkData.GunGameLevels[CurrentLevel-1].GrantedWeapons[RandomNumber];
GunGameLevelGrantWeapon(KFPC_WS, ToGrantWeaponDefinition);
}
}
///////////////////////////////////////////////////////////////////////////////////
function UnregisterPlayer(PlayerController PC)
{
local KFPlayerController_WeeklySurvival KFPC_WS;
super.UnregisterPlayer(PC);
KFPC_WS = KFPlayerController_WeeklySurvival(PC);
if (OutbreakEvent.ActiveEvent.bVIPGameMode)
{
if (KFPC_WS != none && KFPC_WS.VIPGameData.IsVIP)
{
ChooseVIP(false, KFPC_WS);
}
}
}
function WaveStarted()
{
Super.WaveStarted();
if (OutbreakEvent.ActiveEvent.bVIPGameMode)
{
if (WaveNum <= 1)
{
ChooseVIP(true);
}
}
}
function OnVIPDiesEndMatch()
{
local KFPlayerController KFPC;
foreach WorldInfo.AllControllers(class'KFPlayerController', KFPC)
{
KFPC.SetCameraMode('ThirdPerson');
}
WaveEnded(WEC_TeamWipedOut);
}
function ChooseVIP_SetupVIP()
{
local KFPlayerController_WeeklySurvival KFPC_WS, NewVIP;
local KFGameReplicationInfo KFGRI;
NewVIP = none;
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
foreach WorldInfo.AllControllers(class'KFPlayerController_WeeklySurvival', KFPC_WS)
{
if (KFPC_WS != none)
{
if (KFPC_WS.VIPGameData.IsVIP)
{
NewVIP = KFPC_WS;
break;
}
}
}
if (NewVIP != none)
{
//`Log("Setup new VIP: " $NewVIP);
if (NewVIP.Pawn != none)
{
//`Log("Finished setup new VIP: " $NewVIP);
NewVIP.GetPerk().PerkSetOwnerHealthAndArmor(false);
if (NewVIP.VIPGameData.PendingHealthReset)
{
NewVIP.VIPGameData.PendingHealthReset = false;
// Change current health directly, Pawn.HealDamage does a lot of other stuff that can block the healing
NewVIP.Pawn.Health = NewVIP.Pawn.HealthMax;
}
// Replicate new data to clients
KFGRI.UpdateVIPPlayer(KFPlayerReplicationInfo(NewVIP.PlayerReplicationInfo));
KFGRI.UpdateVIPMaxHealth(NewVIP.Pawn.HealthMax);
KFGRI.UpdateVIPCurrentHealth(NewVIP.Pawn.Health);
NewVIP.PlayVIPGameChosenSound(3.5f);
ClearTimer('ChooseVIP_SetupVIP');
}
}
}
function ChooseVIP(bool ForceAddHealth, optional KFPlayerController_WeeklySurvival PlayerJustLeft = none)
{
local int RandomNumber;
local KFPlayerController_WeeklySurvival KFPC_WS, CurrentVIP, NewVIP;
local array<KFPlayerController_WeeklySurvival> PotentialVIP;
local KFGameReplicationInfo KFGRI;
//`Log("ChooseVIP!!!!!");
ClearTimer('ChooseVIP_SetupVIP');
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
foreach WorldInfo.AllControllers(class'KFPlayerController_WeeklySurvival', KFPC_WS)
{
if (KFPC_WS != none)
{
if (KFPC_WS.VIPGameData.IsVIP == false && KFPC_WS.VIPGameData.WasVIP == false)
{
PotentialVIP.AddItem(KFPC_WS);
}
if (KFPC_WS.VIPGameData.IsVIP)
{
CurrentVIP = KFPC_WS;
}
}
}
if (CurrentVIP != none)
{
//`Log("Remove old VIP: " $CurrentVIP);
CurrentVIP.VIPGameData.IsVIP = false;
CurrentVIP.GetPerk().PerkSetOwnerHealthAndArmor(false);
}
// If there's no potential VIP we restart
if (PotentialVIP.Length == 0)
{
foreach WorldInfo.AllControllers(class'KFPlayerController_WeeklySurvival', KFPC_WS)
{
if (KFPC_WS != none)
{
KFPC_WS.VIPGameData.WasVIP = false;
if (PlayerJustLeft == none
|| PlayerJustLeft != KFPC_WS)
{
PotentialVIP.AddItem(KFPC_WS);
}
}
}
}
if (PotentialVIP.Length > 0)
{
RandomNumber = Rand(PotentialVIP.Length);
NewVIP = PotentialVIP[RandomNumber];
NewVIP.VIPGameData.IsVIP = true;
NewVIP.VIPGameData.WasVIP = true;
}
if (NewVIP != none)
{
if (ForceAddHealth || (KFGRI != none && KFGRI.bWaveIsActive == false))
{
NewVIP.VIPGameData.PendingHealthReset = true;
}
// If there's no Pawn we have to wait on a Timer function
if (NewVIP.Pawn != none)
{
ChooseVIP_SetupVIP();
}
else
{
SetTimer(0.25f, true, 'ChooseVIP_SetupVIP');
}
ClearTimer('OnVIPDiesEndMatch');
}
}
function OnOutbreakWaveWon()
{
Super.OnOutbreakWaveWon();
// GunGame Mode
if (OutbreakEvent.ActiveEvent.bGunGameMode)
{
MyKFGRI.GunGameWavesCurrent += 1;
// If we unlocked last weapon we only finish if we completed the boss wave
// If we didn't unlock to last weapon and we just finished last wave (before BOSS), repeat
if (bGunGamePlayerOnLastGun)
{
MyKFGRI.bWaveGunGameIsFinal = true;
if (WaveNum < WaveMax)
{
WaveNum = WaveMax - 1;
}
}
else if (WaveNum >= WaveMax - 1)
{
// Repeat wave before BOSS till forever
WaveNum = WaveMax - 2;
}
MyKFGRI.bNetDirty = true;
}
// VIP Mode
if (OutbreakEvent.ActiveEvent.bVIPGameMode)
{
ChooseVIP(true);
}
}
defaultproperties
{
//Overrides
GameReplicationInfoClass=class'KFGameContent.KFGameReplicationInfo_WeeklySurvival'
PlayerControllerClass=class'KFGame.KFPlayerController_WeeklySurvival'
OutbreakEventClass=class'KFOutbreakEvent_Weekly'
}