KF2-ZedSpawner/ZedSpawner/Classes/ZedSpawner.uc

634 lines
15 KiB
Ucode
Raw Normal View History

2022-05-11 12:43:39 +00:00
class ZedSpawner extends Info
config(ZedSpawner);
2022-05-20 20:45:26 +00:00
const LatestVersion = 1;
2022-05-13 07:02:34 +00:00
const dt = 1;
2022-05-11 12:43:39 +00:00
2022-05-13 07:02:34 +00:00
const CfgSpawn = class'Spawn';
2022-05-16 02:42:13 +00:00
const CfgSpawnListR = class'SpawnListRegular';
2022-05-13 07:02:34 +00:00
const CfgSpawnListBW = class'SpawnListBossWaves';
const CfgSpawnListSW = class'SpawnListSpecialWaves';
2022-05-11 12:43:39 +00:00
enum E_LogLevel
{
LL_WrongLevel,
LL_Fatal,
LL_Error,
LL_Warning,
LL_Info,
LL_Debug,
LL_Trace,
LL_All
};
struct S_SpawnEntry
{
var class<KFPawn_Monster> BossClass;
var class<KFPawn_Monster> ZedClass;
2022-05-20 20:45:26 +00:00
var byte Wave;
2022-05-16 02:42:13 +00:00
var int SpawnCountBase;
var int SingleSpawnLimitDefault;
var int SingleSpawnLimit;
2022-05-11 12:43:39 +00:00
var float Probability;
2022-05-16 02:42:13 +00:00
var float RelativeStartDefault;
var float RelativeStart;
2022-05-11 12:43:39 +00:00
var int DelayDefault;
var int Delay;
2022-05-16 02:42:13 +00:00
var int SpawnsLeft;
var int SpawnsTotal;
2022-05-11 12:43:39 +00:00
var bool SpawnAtPlayerStart;
};
2022-05-20 21:31:35 +00:00
var private config int Version;
var private config E_LogLevel LogLevel;
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
var private Array<S_SpawnEntry> SpawnListR;
2022-05-11 12:43:39 +00:00
var private Array<S_SpawnEntry> SpawnListBW;
var private Array<S_SpawnEntry> SpawnListSW;
var private KFGameInfo_Survival KFGIS;
var private KFGameInfo_Endless KFGIE;
2022-05-20 21:31:35 +00:00
var private KFGI_Access KFGIA;
2022-05-13 07:02:34 +00:00
2022-05-11 12:43:39 +00:00
var private int CurrentWave;
2022-05-20 21:31:35 +00:00
var private int SpecialWave;
2022-05-11 12:43:39 +00:00
var private int CurrentCycle;
var private int CycleWaveShift;
var private int CycleWaveSize;
var private int WaveTotalAI;
2022-05-20 21:31:35 +00:00
var private class<KFPawn_Monster> CurrentBossClass;
2022-05-11 12:43:39 +00:00
var private Array<class<KFPawn_Monster> > BossClassCache;
2022-05-13 07:02:34 +00:00
var private Array<class<KFPawn_Monster> > CustomZeds;
2022-05-11 12:43:39 +00:00
2022-05-20 21:31:35 +00:00
var private String SpawnTimerLastMessage;
2022-05-16 02:42:13 +00:00
delegate bool WaveCondition(S_SpawnEntry SE);
2022-05-20 21:31:35 +00:00
public event PreBeginPlay()
2022-05-16 02:42:13 +00:00
{
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-16 02:42:13 +00:00
2022-05-20 20:45:26 +00:00
if (WorldInfo.NetMode == NM_Client)
2022-05-16 02:42:13 +00:00
{
2022-05-20 20:45:26 +00:00
`ZS_Fatal("NetMode == NM_Client, Destroy...");
Destroy();
return;
2022-05-16 02:42:13 +00:00
}
2022-05-20 20:45:26 +00:00
Super.PreBeginPlay();
2022-05-16 02:42:13 +00:00
}
2022-05-20 21:31:35 +00:00
public event PostBeginPlay()
2022-05-16 02:42:13 +00:00
{
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-16 02:42:13 +00:00
2022-05-20 20:45:26 +00:00
if (bPendingDelete) return;
Super.PostBeginPlay();
Init();
2022-05-16 02:42:13 +00:00
}
2022-05-20 20:45:26 +00:00
private function InitConfig()
2022-05-11 12:43:39 +00:00
{
2022-05-20 20:45:26 +00:00
if (Version == `NO_CONFIG)
{
LogLevel = LL_Info;
SaveConfig();
}
2022-05-11 12:43:39 +00:00
2022-05-20 20:45:26 +00:00
CfgSpawn.static.InitConfig(Version, LatestVersion);
CfgSpawnListR.static.InitConfig(Version, LatestVersion, KFGIA);
CfgSpawnListBW.static.InitConfig(Version, LatestVersion, KFGIA);
CfgSpawnListSW.static.InitConfig(Version, LatestVersion);
2022-05-11 12:43:39 +00:00
2022-05-20 20:45:26 +00:00
switch (Version)
2022-05-11 12:43:39 +00:00
{
2022-05-20 20:45:26 +00:00
case `NO_CONFIG:
`ZS_Info("Config created");
case MaxInt:
`ZS_Info("Config updated to version"@LatestVersion);
break;
case LatestVersion:
`ZS_Info("Config is up-to-date");
break;
default:
`ZS_Warn("The config version is higher than the current version (are you using an old mutator?)");
`ZS_Warn("Config version is" @ Version @ "but current version is" @ LatestVersion);
`ZS_Warn("The config version will be changed to" @ LatestVersion);
break;
}
if (LatestVersion != Version)
{
Version = LatestVersion;
SaveConfig();
2022-05-11 12:43:39 +00:00
}
}
private function Init()
{
2022-05-16 02:42:13 +00:00
local S_SpawnEntry SE;
2022-05-11 12:43:39 +00:00
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
2022-05-20 20:45:26 +00:00
KFGIS = KFGameInfo_Survival(WorldInfo.Game);
if (KFGIS == None)
2022-05-11 12:43:39 +00:00
{
2022-05-20 20:45:26 +00:00
`ZS_Fatal("Incompatible gamemode:" @ WorldInfo.Game $ ". Destroy...");
Destroy();
return;
2022-05-11 12:43:39 +00:00
}
2022-05-20 20:45:26 +00:00
KFGIA = new(KFGIS) class'KFGI_Access';
KFGIE = KFGameInfo_Endless(KFGIS);
InitConfig();
2022-05-11 12:43:39 +00:00
if (LogLevel == LL_WrongLevel)
{
LogLevel = LL_Info;
2022-05-17 09:56:31 +00:00
`ZS_Warn("Wrong 'LogLevel', return to default value");
2022-05-11 12:43:39 +00:00
SaveConfig();
}
`ZS_Log("LogLevel:" @ LogLevel);
if (!CfgSpawn.static.Load(LogLevel))
{
2022-05-17 09:56:31 +00:00
`ZS_Fatal("Wrong settings, Destroy...");
2022-05-11 12:43:39 +00:00
Destroy();
return;
}
2022-05-16 02:42:13 +00:00
SpawnListR = CfgSpawnListR.static.Load(LogLevel);
2022-05-11 12:43:39 +00:00
SpawnListBW = CfgSpawnListBW.static.Load(LogLevel);
SpawnListSW = CfgSpawnListSW.static.Load(KFGIE, LogLevel);
2022-05-20 20:45:26 +00:00
CurrentWave = INDEX_NONE;
2022-05-16 02:42:13 +00:00
SpecialWave = INDEX_NONE;
2022-05-11 12:43:39 +00:00
CurrentCycle = 1;
2022-05-20 20:45:26 +00:00
if (CfgSpawn.default.bCyclicalSpawn)
2022-05-11 12:43:39 +00:00
{
2022-05-20 20:45:26 +00:00
CycleWaveSize = 0;
CycleWaveShift = MaxInt;
foreach SpawnListR(SE)
2022-05-13 07:02:34 +00:00
{
2022-05-20 20:45:26 +00:00
CycleWaveShift = Min(CycleWaveShift, SE.Wave);
CycleWaveSize = Max(CycleWaveSize, SE.Wave);
2022-05-13 07:02:34 +00:00
}
2022-05-20 20:45:26 +00:00
CycleWaveSize = CycleWaveSize - CycleWaveShift + 1;
2022-05-11 12:43:39 +00:00
}
2022-05-20 20:45:26 +00:00
CreateBossCache();
PreloadContent();
SetTimer(float(dt), true, nameof(SpawnTimer));
}
private function CreateBossCache()
{
local S_SpawnEntry SE;
2022-05-13 07:02:34 +00:00
2022-05-16 02:42:13 +00:00
foreach SpawnListBW(SE)
2022-05-20 20:45:26 +00:00
if (BossClassCache.Find(SE.BossClass) == INDEX_NONE)
BossClassCache.AddItem(SE.BossClass);
}
private function PreloadContent()
{
local class<KFPawn_Monster> PawnClass;
ExtractCustomZedsFromSpawnList(SpawnListR, CustomZeds);
ExtractCustomZedsFromSpawnList(SpawnListBW, CustomZeds);
ExtractCustomZedsFromSpawnList(SpawnListSW, CustomZeds);
foreach CustomZeds(PawnClass)
{
`ZS_Info("Preload content:" @ PawnClass);
PawnClass.static.PreloadContent();
}
}
private function ExtractCustomZedsFromSpawnList(Array<S_SpawnEntry> SpawnList, out Array<class<KFPawn_Monster> > Out)
{
local S_SpawnEntry SE;
foreach SpawnList(SE)
2022-05-13 07:02:34 +00:00
{
2022-05-20 20:45:26 +00:00
if (Out.Find(SE.ZedClass) == INDEX_NONE
2022-05-16 02:42:13 +00:00
&& KFGIA.IsCustomZed(SE.ZedClass))
2022-05-13 07:02:34 +00:00
{
2022-05-20 20:45:26 +00:00
Out.AddItem(SE.ZedClass);
2022-05-13 07:02:34 +00:00
}
}
2022-05-20 20:45:26 +00:00
}
public function bool WaveConditionRegular(S_SpawnEntry SE)
{
`ZS_Trace(`Location);
return (SE.Wave == KFGIS.WaveNum - CycleWaveSize * (CurrentCycle - 1));
}
public function bool WaveConditionBoss(S_SpawnEntry SE)
{
local KFPawn_Monster KFPM;
local int Index;
2022-05-13 07:02:34 +00:00
2022-05-20 20:45:26 +00:00
`ZS_Trace(`Location);
if (CurrentBossClass == None)
2022-05-13 07:02:34 +00:00
{
2022-05-20 20:45:26 +00:00
foreach WorldInfo.AllPawns(class'KFPawn_Monster', KFPM)
2022-05-13 07:02:34 +00:00
{
2022-05-20 20:45:26 +00:00
Index = BossClassCache.Find(KFPM.class);
if (Index != INDEX_NONE)
{
CurrentBossClass = BossClassCache[Index];
break;
}
2022-05-13 07:02:34 +00:00
}
}
2022-05-20 20:45:26 +00:00
if (CurrentBossClass == None)
{
return false;
}
return (SE.BossClass == CurrentBossClass);
}
public function bool WaveConditionSpecial(S_SpawnEntry SE)
{
`ZS_Trace(`Location);
return (SE.Wave == SpecialWave);
2022-05-11 12:43:39 +00:00
}
private function SpawnTimer()
{
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
if (KFGIS.WaveNum != 0 && CurrentWave < KFGIS.WaveNum)
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
SetupWave();
2022-05-11 12:43:39 +00:00
}
if (!KFGIS.IsWaveActive())
{
SpawnTimerLogger(true, "wave is not active");
return;
}
if (CfgSpawn.default.AliveSpawnLimit > 0 && KFGIS.AIAliveCount >= CfgSpawn.default.AliveSpawnLimit)
{
SpawnTimerLogger(true, "alive spawn limit reached");
return;
}
if (!KFGIS.MyKFGRI.IsBossWave() && CfgSpawn.default.bShadowSpawn && KFGIS.MyKFGRI.AIRemaining <= KFGIS.AIAliveCount)
{
SpawnTimerLogger(true, "shadow spawn is active and no free spawn slots");
return;
}
SpawnTimerLogger(false);
if ((SpecialWave == INDEX_NONE && !KFGIS.MyKFGRI.IsBossWave())
|| (SpecialWave != INDEX_NONE && !CfgSpawnListSW.default.bStopRegularSpawn)
|| (KFGIS.MyKFGRI.IsBossWave() && !CfgSpawnListBW.default.bStopRegularSpawn))
2022-05-16 02:42:13 +00:00
{
SpawnZeds(SpawnListR, WaveConditionRegular);
}
2022-05-11 12:43:39 +00:00
if (SpecialWave != INDEX_NONE)
2022-05-16 02:42:13 +00:00
{
SpawnZeds(SpawnListSW, WaveConditionSpecial);
}
2022-05-11 12:43:39 +00:00
if (KFGIS.MyKFGRI.IsBossWave())
2022-05-16 02:42:13 +00:00
{
SpawnZeds(SpawnListBW, WaveConditionBoss);
}
2022-05-11 12:43:39 +00:00
}
2022-05-16 02:42:13 +00:00
private function SetupWave()
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
local int WaveTotalAIDef;
2022-05-11 12:43:39 +00:00
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
CurrentWave = KFGIS.WaveNum;
if (!KFGIS.MyKFGRI.IsBossWave())
{
WaveTotalAIDef = KFGIS.SpawnManager.WaveTotalAI;
KFGIS.SpawnManager.WaveTotalAI *= CfgSpawn.default.ZedTotalMultiplier;
WaveTotalAI = KFGIS.SpawnManager.WaveTotalAI;
KFGIS.MyKFGRI.WaveTotalAICount = KFGIS.SpawnManager.WaveTotalAI;
KFGIS.MyKFGRI.AIRemaining = KFGIS.SpawnManager.WaveTotalAI;
if (WaveTotalAIDef != KFGIS.SpawnManager.WaveTotalAI)
{
2022-05-17 09:56:31 +00:00
`ZS_Info("increase WaveTotalAI from" @ WaveTotalAIDef @ "to" @ WaveTotalAI @ "due to ZedTotalMultiplier" @ "(" $ CfgSpawn.default.ZedTotalMultiplier $ ")");
2022-05-16 02:42:13 +00:00
}
}
if (CfgSpawn.default.bCyclicalSpawn && KFGIS.WaveNum > 1 && KFGIS.WaveNum == CycleWaveShift + CycleWaveSize * CurrentCycle)
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
CurrentCycle++;
2022-05-17 09:56:31 +00:00
`ZS_Info("Next spawn cycle started:" @ CurrentCycle);
2022-05-16 02:42:13 +00:00
}
ResetSpawnList(SpawnListR);
ResetSpawnList(SpawnListSW);
ResetSpawnList(SpawnListBW);
CurrentBossClass = None;
if (KFGIE != None)
{
SpecialWave = KFGameReplicationInfo_Endless(KFGIE.GameReplicationInfo).CurrentSpecialMode;
}
}
private function ResetSpawnList(out Array<S_SpawnEntry> List)
{
local S_SpawnEntry SE;
local int Index;
local float Cycle, Players;
local float MSB, MSC, MSP;
local float MLB, MLC, MLP;
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-16 02:42:13 +00:00
Cycle = float(CurrentCycle);
Players = float(PlayerCount());
MSB = CfgSpawn.default.ZedTotalMultiplier;
MSC = CfgSpawn.default.SpawnTotalCycleMultiplier;
MSP = CfgSpawn.default.SpawnTotalPlayerMultiplier;
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
MLB = CfgSpawn.default.SingleSpawnLimitMultiplier;
MLC = CfgSpawn.default.SingleSpawnLimitCycleMultiplier;
MLP = CfgSpawn.default.SingleSpawnLimitPlayerMultiplier;
foreach List(SE, Index)
{
2022-05-11 12:43:39 +00:00
if (KFGIS.MyKFGRI.IsBossWave())
{
2022-05-16 02:42:13 +00:00
List[Index].RelativeStart = 0.f;
List[Index].Delay = SE.DelayDefault;
2022-05-11 12:43:39 +00:00
}
else
{
2022-05-16 02:42:13 +00:00
List[Index].RelativeStart = SE.RelativeStartDefault;
if (SE.RelativeStart == 0.f)
List[Index].Delay = SE.DelayDefault;
2022-05-11 12:43:39 +00:00
else
2022-05-16 02:42:13 +00:00
List[Index].Delay = 0;
2022-05-11 12:43:39 +00:00
}
2022-05-16 02:42:13 +00:00
List[Index].SpawnsTotal = Round(SE.SpawnCountBase * (MSB + MSC * (Cycle - 1.0f) + MSP * (Players - 1.0f)));
List[Index].SpawnsLeft = List[Index].SpawnsTotal;
List[Index].SingleSpawnLimit = Round(SE.SingleSpawnLimitDefault * (MLB + MLC * (Cycle - 1.0f) + MLP * (Players - 1.0f)));
2022-05-17 09:56:31 +00:00
`ZS_Debug(SE.ZedClass @ "SpawnsTotal:" @ List[Index].SpawnsTotal @ "SingleSpawnLimit:" @ List[Index].SingleSpawnLimit);
2022-05-11 12:43:39 +00:00
}
}
private function SpawnTimerLogger(bool Stop, optional String Reason)
{
local String Message;
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
if (Stop)
Message = "Stop spawn";
else
Message = "Start spawn";
if (Reason != "")
Message @= "(" $ Reason $ ")";
if (Message != SpawnTimerLastMessage)
{
2022-05-17 09:56:31 +00:00
`ZS_Info(Message);
2022-05-11 12:43:39 +00:00
SpawnTimerLastMessage = Message;
}
}
2022-05-16 02:42:13 +00:00
private function SpawnZeds(out Array<S_SpawnEntry> SpawnList, delegate<WaveCondition> Condition)
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
local S_SpawnEntry SE;
local int Index;
2022-05-11 12:43:39 +00:00
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
foreach SpawnList(SE, Index)
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
if (Condition(SE))
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
if (!ReadyToStart(SE)) continue;
if (ReadyToSpawn(SE))
SpawnEntry(SpawnListR, Index);
else
SpawnListR[Index].Delay -= dt;
2022-05-11 12:43:39 +00:00
}
}
}
2022-05-16 02:42:13 +00:00
private function bool ReadyToStart(S_SpawnEntry SE)
2022-05-11 12:43:39 +00:00
{
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-16 02:42:13 +00:00
if (SE.RelativeStart == 0.f)
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
return true;
}
else
{
return (SE.RelativeStart <= 1.0f - (float(KFGIS.MyKFGRI.AIRemaining) / float(WaveTotalAI)));
2022-05-11 12:43:39 +00:00
}
}
2022-05-16 02:42:13 +00:00
private function bool ReadyToSpawn(S_SpawnEntry SE)
2022-05-11 12:43:39 +00:00
{
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
return SE.Delay <= 0 && SE.SpawnsLeft > 0;
2022-05-11 12:43:39 +00:00
}
2022-05-16 02:42:13 +00:00
private function SpawnEntry(out Array<S_SpawnEntry> SpawnList, int Index)
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
local S_SpawnEntry SE;
local int FreeSpawnSlots, SpawnCount, Spawned;
local String Message;
2022-05-11 12:43:39 +00:00
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
SE = SpawnList[Index];
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
SpawnList[Index].Delay = SE.DelayDefault;
if (FRand() <= SE.Probability)
2022-05-11 12:43:39 +00:00
{
2022-05-16 02:42:13 +00:00
if (SE.SingleSpawnLimit == 0 || SE.SpawnsLeft < SE.SingleSpawnLimit)
SpawnCount = SE.SpawnsLeft;
else
SpawnCount = SE.SingleSpawnLimit;
if (CfgSpawn.default.bShadowSpawn && !KFGIS.MyKFGRI.IsBossWave())
{
FreeSpawnSlots = KFGIS.MyKFGRI.AIRemaining - KFGIS.AIAliveCount;
if (SpawnCount > FreeSpawnSlots)
{
2022-05-17 09:56:31 +00:00
`ZS_Info("Not enough free slots to spawn, will spawn" @ FreeSpawnSlots @ "instead of" @ SpawnCount);
2022-05-16 02:42:13 +00:00
SpawnCount = FreeSpawnSlots;
}
}
Spawned = SpawnZed(SE.ZedClass, SpawnCount, SE.SpawnAtPlayerStart);
Message = "Spawned:" @ SE.ZedClass @ "x" $ Spawned;
2022-05-11 12:43:39 +00:00
}
else
{
2022-05-16 02:42:13 +00:00
Message = "Skip spawn" @ SE.ZedClass @ "due to probability:" @ SE.Probability * 100 $ "%";
Spawned = SE.SingleSpawnLimit;
2022-05-11 12:43:39 +00:00
}
2022-05-16 02:42:13 +00:00
SpawnList[Index].SpawnsLeft -= Spawned;
if (SpawnList[Index].SpawnsLeft > 0)
{
Message @= "(Next spawn after" @ SE.DelayDefault $ "sec," @ "spawns left:" @ SpawnList[Index].SpawnsLeft $ ")";
}
2022-05-17 09:56:31 +00:00
`ZS_Info(Message);
2022-05-11 12:43:39 +00:00
}
private function int PlayerCount()
{
local PlayerController PC;
local int HumanPlayers;
local KFOnlineGameSettings KFGameSettings;
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
if (KFGIS.PlayfabInter != None && KFGIS.PlayfabInter.GetGameSettings() != None)
{
KFGameSettings = KFOnlineGameSettings(KFGIS.PlayfabInter.GetGameSettings());
HumanPlayers = KFGameSettings.NumPublicConnections - KFGameSettings.NumOpenPublicConnections;
}
else
{
HumanPlayers = 0;
foreach WorldInfo.AllControllers(class'PlayerController', PC)
if (PC.bIsPlayer
&& PC.PlayerReplicationInfo != None
&& !PC.PlayerReplicationInfo.bOnlySpectator
&& !PC.PlayerReplicationInfo.bBot)
HumanPlayers++;
}
return HumanPlayers;
}
private function Vector PlayerStartLocation()
{
local PlayerController PC;
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
foreach WorldInfo.AllControllers(class'PlayerController', PC)
return KFGIS.FindPlayerStart(PC, 0).Location;
return KFGIS.FindPlayerStart(None, 0).Location;
}
2022-05-16 02:42:13 +00:00
private function int SpawnZed(class<KFPawn_Monster> ZedClass, int SpawnCount, bool SpawnAtPlayerStart)
2022-05-11 12:43:39 +00:00
{
local Array<class<KFPawn_Monster> > CustomSquad;
local Vector SpawnLocation;
local KFPawn_Monster KFPM;
local Controller C;
local int SpawnFailed;
2022-05-16 02:42:13 +00:00
local int Index;
2022-05-11 12:43:39 +00:00
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
2022-05-16 02:42:13 +00:00
for (Index = 0; Index < SpawnCount; Index++)
2022-05-11 12:43:39 +00:00
CustomSquad.AddItem(ZedClass);
if (SpawnAtPlayerStart)
{
SpawnLocation = PlayerStartLocation();
SpawnLocation.Y += 64;
SpawnLocation.Z += 64;
}
else
{
SpawnLocation = KFGIS.SpawnManager.GetBestSpawnVolume(CustomSquad).Location;
SpawnLocation.Z += 10;
}
SpawnFailed = 0;
2022-05-16 02:42:13 +00:00
for (Index = 0; Index < SpawnCount; Index++)
2022-05-11 12:43:39 +00:00
{
KFPM = Spawn(ZedClass,,, SpawnLocation, rot(0,0,1),, true);
if (KFPM == None)
{
2022-05-17 09:56:31 +00:00
`ZS_Error("Can't spawn" @ ZedClass);
2022-05-11 12:43:39 +00:00
SpawnFailed++;
continue;
}
C = KFPM.Spawn(KFPM.ControllerClass);
if (C == None)
{
2022-05-17 09:56:31 +00:00
`ZS_Error("Can't spawn controller for" @ ZedClass $ ". Destroy this KFPawn...");
2022-05-11 12:43:39 +00:00
KFPM.Destroy();
SpawnFailed++;
continue;
}
C.Possess(KFPM, false);
}
if (CfgSpawn.default.bShadowSpawn && !KFGIS.MyKFGRI.IsBossWave())
{
2022-05-16 02:42:13 +00:00
KFGIS.MyKFGRI.AIRemaining -= (SpawnCount - SpawnFailed);
2022-05-11 12:43:39 +00:00
}
KFGIS.RefreshMonsterAliveCount();
2022-05-16 02:42:13 +00:00
return SpawnCount - SpawnFailed;
2022-05-11 12:43:39 +00:00
}
2022-05-13 07:02:34 +00:00
public function NotifyLogin(Controller C)
{
local ZedSpawnerRepLink RepLink;
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-13 07:02:34 +00:00
RepLink = Spawn(class'ZedSpawnerRepLink', C);
RepLink.LogLevel = LogLevel;
RepLink.CustomZeds = CustomZeds;
RepLink.ServerSync();
}
public function NotifyLogout(Controller C)
2022-05-11 12:43:39 +00:00
{
2022-05-17 09:56:31 +00:00
`ZS_Trace(`Location);
2022-05-11 12:43:39 +00:00
2022-05-13 07:02:34 +00:00
return;
}
DefaultProperties
{
2022-05-11 12:43:39 +00:00
}