Compare commits
8 Commits
SpawnManag
...
v1.0.3
Author | SHA1 | Date | |
---|---|---|---|
fd3c9116e4 | |||
b5355d9fb5 | |||
62c3f79c5e | |||
d466d1fc79 | |||
f0b10fb158 | |||
b0727dd677 | |||
25b3e85009 | |||
41f186ee15 |
7
PublicationContent/description.txt
Normal file
7
PublicationContent/description.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[h1]ZedSpawner[/h1]
|
||||||
|
|
||||||
|
[h1]Description[/h1]
|
||||||
|
Work In Progress...
|
||||||
|
|
||||||
|
[h1]Sources[/h1]
|
||||||
|
[url=https://github.com/GenZmeY/KF2-ZedSpawner]https://github.com/GenZmeY/KF2-ZedSpawner[/url]
|
BIN
PublicationContent/preview.png
Normal file
BIN
PublicationContent/preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 418 KiB |
BIN
PublicationContent/preview.psd
Normal file
BIN
PublicationContent/preview.psd
Normal file
Binary file not shown.
1
PublicationContent/tags.txt
Normal file
1
PublicationContent/tags.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Mutators
|
1
PublicationContent/title.txt
Normal file
1
PublicationContent/title.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
ZedSpawner
|
@ -1,350 +0,0 @@
|
|||||||
class AISpawnManager extends KFAISpawnManager
|
|
||||||
abstract;
|
|
||||||
|
|
||||||
const class<Config_SpawnManager> Config;
|
|
||||||
|
|
||||||
struct S_DifficultyWaveInfo
|
|
||||||
{
|
|
||||||
var Array<AIWaveInfo> Waves;
|
|
||||||
};
|
|
||||||
|
|
||||||
var protected ZedSpawner ZS;
|
|
||||||
|
|
||||||
var protected Array<S_DifficultyWaveInfo> V_DifficultyWaveSettings;
|
|
||||||
var protected S_DifficultyWaveInfo V_WaveSettings;
|
|
||||||
var protected Array<AISpawnSquad> V_AvailableSquads;
|
|
||||||
|
|
||||||
var public E_LogLevel LogLevel;
|
|
||||||
|
|
||||||
private function CopySpawnSquadArray(Array<KFAISpawnSquad> From, out Array<AISpawnSquad> To)
|
|
||||||
{
|
|
||||||
local KFAISpawnSquad SS;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
To.Length = 0;
|
|
||||||
foreach From(SS)
|
|
||||||
To.AddItem(class'AISpawnSquad'.static.CreateFrom(SS));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function ZedSpawner GetZedSpawner()
|
|
||||||
{
|
|
||||||
foreach WorldInfo.DynamicActors(class'ZedSpawner', ZS)
|
|
||||||
return ZS;
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function Initialize()
|
|
||||||
{
|
|
||||||
ZS = GetZedSpawner();
|
|
||||||
if (ZS != None)
|
|
||||||
{
|
|
||||||
LogLevel = ZS.LogLevel;
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
`ZS_Log("FATAL: no ZedSpawner found! Destroy" @ Self.class);
|
|
||||||
`ZS_Log("FATAL:" @ `Location);
|
|
||||||
Destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
|
|
||||||
Super.Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetWaveSettings(out DifficultyWaveInfo WaveInfo)
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
if (DifficultyWaveSettings.Length > 0)
|
|
||||||
WaveInfo = DifficultyWaveSettings[Clamp(GameDifficulty, 0, DifficultyWaveSettings.Length - 1)];
|
|
||||||
|
|
||||||
V_GetWaveSettings(V_WaveSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function V_GetWaveSettings(out S_DifficultyWaveInfo WaveInfo)
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
if (V_DifficultyWaveSettings.Length > 0)
|
|
||||||
WaveInfo = V_DifficultyWaveSettings[Clamp(GameDifficulty, 0, V_DifficultyWaveSettings.Length - 1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function SetupNextWave(byte NextWaveIndex, int TimeToNextWaveBuffer = 0)
|
|
||||||
{
|
|
||||||
local KFGameReplicationInfo KFGRI;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
if (OutbreakEvent.ActiveEvent.bBossRushMode)
|
|
||||||
{
|
|
||||||
NextWaveIndex = MyKFGRI.WaveMax - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NextWaveIndex < V_WaveSettings.Waves.Length)
|
|
||||||
{
|
|
||||||
if (GameDifficulty < RecycleSpecialSquad.Length)
|
|
||||||
{
|
|
||||||
bRecycleSpecialSquad = RecycleSpecialSquad[GameDifficulty];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bRecycleSpecialSquad = RecycleSpecialSquad[RecycleSpecialSquad.Length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
LeftoverSpawnSquad.Length = 0;
|
|
||||||
NumSpawnListCycles = 1;
|
|
||||||
NumSpecialSquadRecycles = 0;
|
|
||||||
|
|
||||||
if (MyKFGRI.IsBossWave() || OutbreakEvent.ActiveEvent.bBossRushMode)
|
|
||||||
{
|
|
||||||
WaveTotalAI = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (V_WaveSettings.Waves[NextWaveIndex].bRecycleWave)
|
|
||||||
{
|
|
||||||
WaveTotalAI = V_WaveSettings.Waves[NextWaveIndex].MaxAI *
|
|
||||||
DifficultyInfo.GetPlayerNumMaxAIModifier(GetNumHumanTeamPlayers()) *
|
|
||||||
DifficultyInfo.GetDifficultyMaxAIModifier();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WaveTotalAI = V_WaveSettings.Waves[NextWaveIndex].MaxAI;
|
|
||||||
}
|
|
||||||
WaveTotalAI *= GetTotalWaveCountScale();
|
|
||||||
WaveTotalAI = Max(1, WaveTotalAI);
|
|
||||||
}
|
|
||||||
|
|
||||||
GetAvailableSquads(NextWaveIndex, true);
|
|
||||||
|
|
||||||
WaveStartTime = WorldInfo.TimeSeconds;
|
|
||||||
TimeUntilNextSpawn = 5.f + TimeToNextWaveBuffer;
|
|
||||||
|
|
||||||
if (NextWaveIndex == 0)
|
|
||||||
{
|
|
||||||
TotalWavesActiveTime = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
|
|
||||||
if (KFGRI != None && (KFGRI.bDebugSpawnManager || KFGRI.bGameConductorGraphingEnabled))
|
|
||||||
{
|
|
||||||
KFGRI.CurrentSineMod = GetSineMod();
|
|
||||||
KFGRI.CurrentNextSpawnTime = TimeUntilNextSpawn;
|
|
||||||
KFGRI.CurrentSineWavFreq = GetSineWaveFreq();
|
|
||||||
KFGRI.CurrentNextSpawnTimeMod = GetNextSpawnTimeMod();
|
|
||||||
KFGRI.CurrentTotalWavesActiveTime = TotalWavesActiveTime;
|
|
||||||
KFGRI.CurrentMaxMonsters = GetMaxMonsters();
|
|
||||||
KFGRI.CurrentTimeTilNextSpawn = TimeUntilNextSpawn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LastAISpawnVolume = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetAvailableSquads(byte MyWaveIndex, optional bool bNeedsSpecialSquad=false)
|
|
||||||
{
|
|
||||||
local int i, j, TotalZedsInSquads;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
if (V_WaveSettings.Waves[MyWaveIndex] != None)
|
|
||||||
{
|
|
||||||
NumSpawnListCycles++;
|
|
||||||
|
|
||||||
V_WaveSettings.Waves[MyWaveIndex].GetNewSquadList(V_AvailableSquads);
|
|
||||||
|
|
||||||
if (bNeedsSpecialSquad)
|
|
||||||
{
|
|
||||||
V_WaveSettings.Waves[MyWaveIndex].GetSpecialSquad(V_AvailableSquads);
|
|
||||||
|
|
||||||
for (i = 0; i < V_AvailableSquads.Length; i++)
|
|
||||||
{
|
|
||||||
for (j = 0; j < V_AvailableSquads[i].MonsterList.Length; j++)
|
|
||||||
{
|
|
||||||
TotalZedsInSquads += V_AvailableSquads[i].MonsterList[j].Num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WaveTotalAI < TotalZedsInSquads)
|
|
||||||
{
|
|
||||||
bForceRequiredSquad = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function V_GetSpawnListFromSquad(byte SquadIdx, out Array<AISpawnSquad> SquadsList, out Array<class<KFPawn_Monster> > AISpawnList)
|
|
||||||
{
|
|
||||||
local AISpawnSquad Squad;
|
|
||||||
local EAIType AIType;
|
|
||||||
local int i, j, RandNum;
|
|
||||||
local ESquadType LargestMonsterSquadType;
|
|
||||||
local Array<class<KFPawn_Monster> > TempSpawnList;
|
|
||||||
local int RandBossIndex;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
Squad = SquadsList[SquadIdx];
|
|
||||||
|
|
||||||
LargestMonsterSquadType = EST_Crawler;
|
|
||||||
|
|
||||||
for (i = 0; i < Squad.MonsterList.Length; i++)
|
|
||||||
{
|
|
||||||
for (j = 0; j < Squad.MonsterList[i].Num; j++)
|
|
||||||
{
|
|
||||||
if (Squad.MonsterList[i].CustomClass != None)
|
|
||||||
{
|
|
||||||
TempSpawnList.AddItem(Squad.MonsterList[i].CustomClass);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AIType = Squad.MonsterList[i].Type;
|
|
||||||
if (AIType == AT_BossRandom)
|
|
||||||
{
|
|
||||||
if (OutbreakEvent.ActiveEvent.bBossRushMode)
|
|
||||||
{
|
|
||||||
RandBossIndex = Rand(BossRushEnemies.length);
|
|
||||||
TempSpawnList.AddItem( default.AIBossClassList[BossRushEnemies[RandBossIndex]]);
|
|
||||||
BossRushEnemies.Remove(RandBossIndex, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TempSpawnList.AddItem(GetBossAISpawnType());
|
|
||||||
}
|
|
||||||
|
|
||||||
LargestMonsterSquadType = EST_Boss;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TempSpawnList.AddItem(GetAISpawnType(AIType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TempSpawnList[TempSpawnList.Length - 1].default.MinSpawnSquadSizeType < LargestMonsterSquadType)
|
|
||||||
{
|
|
||||||
LargestMonsterSquadType = TempSpawnList[TempSpawnList.Length - 1].default.MinSpawnSquadSizeType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (TempSpawnList.Length > 0)
|
|
||||||
{
|
|
||||||
while (TempSpawnList.Length > 0)
|
|
||||||
{
|
|
||||||
RandNum = Rand( TempSpawnList.Length);
|
|
||||||
AISpawnList.AddItem( TempSpawnList[RandNum]);
|
|
||||||
TempSpawnList.Remove( RandNum, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
DesiredSquadType = Squad.MinVolumeType;
|
|
||||||
|
|
||||||
if (LargestMonsterSquadType < DesiredSquadType)
|
|
||||||
{
|
|
||||||
DesiredSquadType = LargestMonsterSquadType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function Array<class<KFPawn_Monster> > GetNextSpawnList()
|
|
||||||
{
|
|
||||||
local Array<class<KFPawn_Monster> > NewSquad, RequiredSquad;
|
|
||||||
local int RandNum, AINeeded;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
if (LeftoverSpawnSquad.Length > 0)
|
|
||||||
{
|
|
||||||
NewSquad = LeftoverSpawnSquad;
|
|
||||||
SetDesiredSquadTypeForZedList(NewSquad);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!IsAISquadAvailable())
|
|
||||||
{
|
|
||||||
if (!bSummoningBossMinions)
|
|
||||||
{
|
|
||||||
if (bRecycleSpecialSquad && NumSpawnListCycles % 2 == 1 && (MaxSpecialSquadRecycles == -1 || NumSpecialSquadRecycles < MaxSpecialSquadRecycles))
|
|
||||||
{
|
|
||||||
GetAvailableSquads(MyKFGRI.WaveNum - 1, true);
|
|
||||||
++NumSpecialSquadRecycles;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GetAvailableSquads(MyKFGRI.WaveNum - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CopySpawnSquadArray(BossMinionsSpawnSquads, V_AvailableSquads);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RandNum = Rand(V_AvailableSquads.Length);
|
|
||||||
|
|
||||||
if (bForceRequiredSquad && RandNum == (V_AvailableSquads.Length - 1))
|
|
||||||
{
|
|
||||||
bForceRequiredSquad=false;
|
|
||||||
}
|
|
||||||
|
|
||||||
V_GetSpawnListFromSquad(RandNum, V_AvailableSquads, NewSquad);
|
|
||||||
|
|
||||||
if (bForceRequiredSquad)
|
|
||||||
{
|
|
||||||
V_GetSpawnListFromSquad((V_AvailableSquads.Length - 1), V_AvailableSquads, RequiredSquad);
|
|
||||||
|
|
||||||
if ((NumAISpawnsQueued + NewSquad.Length + RequiredSquad.Length) > WaveTotalAI)
|
|
||||||
{
|
|
||||||
NewSquad = RequiredSquad;
|
|
||||||
RandNum = (V_AvailableSquads.Length - 1);
|
|
||||||
bForceRequiredSquad=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
V_AvailableSquads.Remove(RandNum, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
AINeeded = GetNumAINeeded();
|
|
||||||
if (AINeeded < NewSquad.Length)
|
|
||||||
{
|
|
||||||
LeftoverSpawnSquad = NewSquad;
|
|
||||||
LeftoverSpawnSquad.Remove(0, AINeeded);
|
|
||||||
NewSquad.Length = AINeeded;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LeftoverSpawnSquad.Length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewSquad;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function bool IsAISquadAvailable()
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
return (V_AvailableSquads.Length > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function SummonBossMinions(Array<KFAISpawnSquad> NewMinionSquad, int NewMaxBossMinions, optional bool bUseLivingPlayerScale = true)
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
CopySpawnSquadArray(NewMinionSquad, V_AvailableSquads);
|
|
||||||
Super.SummonBossMinions(NewMinionSquad, NewMaxBossMinions, bUseLivingPlayerScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function StopSummoningBossMinions()
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
V_AvailableSquads.Length = 0;
|
|
||||||
Super.StopSummoningBossMinions();
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
Config = class'Config_SpawnManager'
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
class AISpawnManager_Endless extends AISpawnManager
|
|
||||||
within KFGameInfo_Endless;
|
|
||||||
|
|
||||||
struct S_MacroDifficultyWaveInfo
|
|
||||||
{
|
|
||||||
var Array<S_DifficultyWaveInfo> MacroDifficultyWaveSettings;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MacroDifficultyWaveInfo
|
|
||||||
{
|
|
||||||
var Array<DifficultyWaveInfo> MacroDifficultyWaveSettings;
|
|
||||||
};
|
|
||||||
|
|
||||||
var protected Array<MacroDifficultyWaveInfo> DifficultyWaves;
|
|
||||||
var protected Array<S_MacroDifficultyWaveInfo> V_DifficultyWaves;
|
|
||||||
|
|
||||||
public function SetupNextWave(byte NextWaveIndex, int TimeToNextWaveBuffer = 0)
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
Super.SetupNextWave(NextWaveIndex % WaveSettings.Waves.length, TimeToNextWaveBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetAvailableSquads(byte MyWaveIndex, optional bool bNeedsSpecialSquad = false)
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
Super.GetAvailableSquads(MyWaveIndex % WaveSettings.Waves.length, bNeedsSpecialSquad);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetWaveSettings(out DifficultyWaveInfo WaveInfo)
|
|
||||||
{
|
|
||||||
local int AdGD; // AdjustedGameDifficulty
|
|
||||||
local int AvAdGD; // AvailableAdjustedGameDifficulty
|
|
||||||
local int AvGD; // AvailableGameDifficulty
|
|
||||||
local int DWL; // DifficultyWavesLength
|
|
||||||
local int MDWSL; // MacroDifficultyWaveSettingsLength
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
DWL = DifficultyWaves.Length;
|
|
||||||
if (DWL > 0)
|
|
||||||
{
|
|
||||||
AvGD = Clamp(GameDifficulty, 0, DWL - 1);
|
|
||||||
MDWSL = DifficultyWaves[AvGD].MacroDifficultyWaveSettings.Length;
|
|
||||||
if (MDWSL > 0)
|
|
||||||
{
|
|
||||||
AdGD = EndlessDifficulty.GetCurrentDifficultyIndex();
|
|
||||||
AvAdGD = Clamp(AdGD, 0, MDWSL - 1);
|
|
||||||
WaveInfo = DifficultyWaves[AvGD].MacroDifficultyWaveSettings[AvAdGD];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
V_GetWaveSettings(V_WaveSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function V_GetWaveSettings(out S_DifficultyWaveInfo WaveInfo)
|
|
||||||
{
|
|
||||||
local int AdGD; // AdjustedGameDifficulty
|
|
||||||
local int AvAdGD; // AvailableAdjustedGameDifficulty
|
|
||||||
local int AvGD; // AvailableGameDifficulty
|
|
||||||
local int VDWL; // V_DifficultyWavesLength
|
|
||||||
local int MDWSL; // MacroDifficultyWaveSettingsLength
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
VDWL = V_DifficultyWaves.Length;
|
|
||||||
if (VDWL > 0)
|
|
||||||
{
|
|
||||||
AvGD = Clamp(GameDifficulty, 0, VDWL - 1);
|
|
||||||
MDWSL = V_DifficultyWaves[AvGD].MacroDifficultyWaveSettings.Length;
|
|
||||||
if (MDWSL > 0)
|
|
||||||
{
|
|
||||||
AdGD = EndlessDifficulty.GetCurrentDifficultyIndex();
|
|
||||||
AvAdGD = Clamp(AdGD, 0, MDWSL - 1);
|
|
||||||
WaveInfo = V_DifficultyWaves[AvGD].MacroDifficultyWaveSettings[AvAdGD];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function OnDifficultyUpdated()
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
GetWaveSettings(WaveSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function OnBossDied()
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
BossMinionsSpawnSquads.length = 0;
|
|
||||||
AvailableSquads.length = 0;
|
|
||||||
V_AvailableSquads.length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function float GetNextSpawnTimeMod()
|
|
||||||
{
|
|
||||||
local float SpawnTimeMod, SpawnTimeModMin;
|
|
||||||
local int TempModIdx;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
SpawnTimeMod = super.GetNextSpawnTimeMod();
|
|
||||||
|
|
||||||
if (MyKFGRI.IsSpecialWave(TempModIdx))
|
|
||||||
{
|
|
||||||
SpawnTimeModMin = EndlessDifficulty.GetSpecialWaveSpawnTimeModMin(SpecialWaveType);
|
|
||||||
SpawnTimeMod = Max(SpawnTimeMod, SpawnTimeModMin);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SpawnTimeMod;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
Config = class'Config_SpawnManager_Endless'
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
class AISpawnManager_Long extends AISpawnManager;
|
|
||||||
|
|
||||||
DefaultProperties
|
|
||||||
{
|
|
||||||
Config = class'Config_SpawnManager_Long'
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
class AISpawnManager_Normal extends AISpawnManager;
|
|
||||||
|
|
||||||
DefaultProperties
|
|
||||||
{
|
|
||||||
Config = class'Config_SpawnManager_Normal'
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
class AISpawnManager_Short extends AISpawnManager;
|
|
||||||
|
|
||||||
DefaultProperties
|
|
||||||
{
|
|
||||||
Config = class'Config_SpawnManager_Short'
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
class AISpawnSquad extends Object
|
|
||||||
hidecategories(Object);
|
|
||||||
|
|
||||||
struct S_AISquadElement
|
|
||||||
{
|
|
||||||
var() EAIType Type;
|
|
||||||
var() byte Num <ClampMin=1 | ClampMax=6>;
|
|
||||||
|
|
||||||
var class<KFPawn_Monster> CustomClass;
|
|
||||||
|
|
||||||
structdefaultproperties
|
|
||||||
{
|
|
||||||
Num = 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var() ESquadType MinVolumeType;
|
|
||||||
var() array<S_AISquadElement> MonsterList;
|
|
||||||
|
|
||||||
public function AISpawnSquad InitFrom(KFAISpawnSquad SpawnSquad)
|
|
||||||
{
|
|
||||||
local AISquadElement SE;
|
|
||||||
local S_AISquadElement SSE;
|
|
||||||
|
|
||||||
MinVolumeType = SpawnSquad.MinVolumeType;
|
|
||||||
|
|
||||||
foreach SpawnSquad.MonsterList(SE)
|
|
||||||
{
|
|
||||||
SSE.Type = SE.Type;
|
|
||||||
SSE.Num = SE.Num;
|
|
||||||
SSE.CustomClass = SE.CustomClass;
|
|
||||||
MonsterList.AddItem(SSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function AISpawnSquad CreateFrom(KFAISpawnSquad SpawnSquad)
|
|
||||||
{
|
|
||||||
local AISquadElement SE;
|
|
||||||
local S_AISquadElement SSE;
|
|
||||||
local AISpawnSquad NewSpawnSquad;
|
|
||||||
|
|
||||||
NewSpawnSquad = new class'AISpawnSquad';
|
|
||||||
NewSpawnSquad.MinVolumeType = SpawnSquad.MinVolumeType;
|
|
||||||
|
|
||||||
foreach SpawnSquad.MonsterList(SE)
|
|
||||||
{
|
|
||||||
SSE.Type = SE.Type;
|
|
||||||
SSE.Num = SE.Num;
|
|
||||||
SSE.CustomClass = SE.CustomClass;
|
|
||||||
NewSpawnSquad.MonsterList.AddItem(SSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewSpawnSquad;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
MinVolumeType = EST_Medium
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
class AIWaveInfo extends Object
|
|
||||||
dependson(AISpawnSquad)
|
|
||||||
hidecategories(Object);
|
|
||||||
|
|
||||||
var() bool bRecycleWave;
|
|
||||||
var() Array<AISpawnSquad> Squads;
|
|
||||||
var() Array<AISpawnSquad> SpecialSquads;
|
|
||||||
var() int MaxAI<ClampMin=1|ClampMax=200|DisplayName=TotalAIBase>;
|
|
||||||
var() Array<AISpawnSquad> EventSquads;
|
|
||||||
|
|
||||||
public function GetNewSquadList(out Array<AISpawnSquad> out_SquadList)
|
|
||||||
{
|
|
||||||
local AISpawnSquad SS;
|
|
||||||
|
|
||||||
out_SquadList.Length = 0;
|
|
||||||
foreach Squads(SS)
|
|
||||||
if (SS != None)
|
|
||||||
out_SquadList.AddItem(SS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetSpecialSquad(out Array<AISpawnSquad> out_SquadList)
|
|
||||||
{
|
|
||||||
if (SpecialSquads.Length > 0)
|
|
||||||
out_SquadList.AddItem(SpecialSquads[Rand(SpecialSquads.Length)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetEventSquadList(out Array<AISpawnSquad> out_SquadList)
|
|
||||||
{
|
|
||||||
local AISpawnSquad SS;
|
|
||||||
|
|
||||||
out_SquadList.Length = 0;
|
|
||||||
foreach EventSquads(SS)
|
|
||||||
if (SS != None)
|
|
||||||
out_SquadList.AddItem(SS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function InitFrom(KFAIWaveInfo WaveInfo)
|
|
||||||
{
|
|
||||||
local KFAISpawnSquad KFSS;
|
|
||||||
|
|
||||||
bRecycleWave = WaveInfo.bRecycleWave;
|
|
||||||
MaxAI = WaveInfo.MaxAI;
|
|
||||||
|
|
||||||
Squads.Length = 0;
|
|
||||||
foreach WaveInfo.Squads(KFSS)
|
|
||||||
Squads.AddItem(class'AISpawnSquad'.static.CreateFrom(KFSS));
|
|
||||||
|
|
||||||
SpecialSquads.Length = 0;
|
|
||||||
foreach WaveInfo.SpecialSquads(KFSS)
|
|
||||||
SpecialSquads.AddItem(class'AISpawnSquad'.static.CreateFrom(KFSS));
|
|
||||||
|
|
||||||
EventSquads.Length = 0;
|
|
||||||
foreach WaveInfo.EventSquads(KFSS)
|
|
||||||
EventSquads.AddItem(class'AISpawnSquad'.static.CreateFrom(KFSS));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function AIWaveInfo CreateFrom(KFAIWaveInfo WaveInfo)
|
|
||||||
{
|
|
||||||
local AIWaveInfo AIWI;
|
|
||||||
|
|
||||||
AIWI = new class'AIWaveInfo';
|
|
||||||
AIWI.InitFrom(WaveInfo);
|
|
||||||
|
|
||||||
return AIWI;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
bRecycleWave = true
|
|
||||||
MaxAI = 32
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
class Config_SpawnManager extends Object
|
|
||||||
config(ZedSpawner);
|
|
||||||
|
|
||||||
var const class<KFAISpawnManager> DefSpawnManager;
|
|
||||||
|
|
||||||
public static function InitConfig()
|
|
||||||
{
|
|
||||||
local DifficultyWaveInfo DWI;
|
|
||||||
local KFAIWaveInfo KFAIWI;
|
|
||||||
local AIWaveInfo AIWI;
|
|
||||||
local int Diff, Wave;
|
|
||||||
|
|
||||||
`ZS_Log("InitConfig:" @ default.DefSpawnManager);
|
|
||||||
foreach default.DefSpawnManager.default.DifficultyWaveSettings(DWI, Diff)
|
|
||||||
{
|
|
||||||
`ZS_Log(" Diff:" @ Diff);
|
|
||||||
foreach DWI.Waves(KFAIWI, Wave)
|
|
||||||
{
|
|
||||||
`ZS_Log(" Wave:" @ Wave);
|
|
||||||
AIWI = class'AIWaveInfo'.static.CreateFrom(KFAIWI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//StaticSaveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function bool Load(E_LogLevel LogLevel)
|
|
||||||
{
|
|
||||||
local bool Errors;
|
|
||||||
Errors = false;
|
|
||||||
return !Errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
DefSpawnManager = class'KFAISpawnManager'
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
class Config_SpawnManager_Endless extends Config_SpawnManager
|
|
||||||
config(ZedSpawner);
|
|
||||||
|
|
||||||
public static function bool Load(E_LogLevel LogLevel)
|
|
||||||
{
|
|
||||||
local bool Errors;
|
|
||||||
Errors = false;
|
|
||||||
return !Errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
DefSpawnManager = class'KFAISpawnManager_Endless'
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
class Config_SpawnManager_Long extends Config_SpawnManager
|
|
||||||
config(ZedSpawner);
|
|
||||||
|
|
||||||
public static function bool Load(E_LogLevel LogLevel)
|
|
||||||
{
|
|
||||||
local bool Errors;
|
|
||||||
Errors = false;
|
|
||||||
return !Errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
DefSpawnManager = class'KFAISpawnManager_Long'
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
class Config_SpawnManager_Normal extends Config_SpawnManager
|
|
||||||
config(ZedSpawner);
|
|
||||||
|
|
||||||
public static function bool Load(E_LogLevel LogLevel)
|
|
||||||
{
|
|
||||||
local bool Errors;
|
|
||||||
Errors = false;
|
|
||||||
return !Errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
DefSpawnManager = class'KFAISpawnManager_Normal'
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
class Config_SpawnManager_Short extends Config_SpawnManager
|
|
||||||
config(ZedSpawner);
|
|
||||||
|
|
||||||
public static function bool Load(E_LogLevel LogLevel)
|
|
||||||
{
|
|
||||||
local bool Errors;
|
|
||||||
Errors = false;
|
|
||||||
return !Errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
DefSpawnManager = class'KFAISpawnManager_Short'
|
|
||||||
}
|
|
@ -1,184 +0,0 @@
|
|||||||
class Config_SpawnManager_WaveInfo extends Object
|
|
||||||
abstract
|
|
||||||
config(ZedSpawnManager);
|
|
||||||
|
|
||||||
var const class<KFAISpawnManager> DefSpawnManager;
|
|
||||||
var const byte Difficulty;
|
|
||||||
var const byte Wave;
|
|
||||||
|
|
||||||
struct Unit
|
|
||||||
{
|
|
||||||
var int Num;
|
|
||||||
var String ZedClass;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Squad
|
|
||||||
{
|
|
||||||
var ESquadType MinVolumeType;
|
|
||||||
var Array<Unit> Units;
|
|
||||||
};
|
|
||||||
|
|
||||||
var config bool bRecycleWave;
|
|
||||||
var config int MaxAI;
|
|
||||||
var config Array<Squad> Squads;
|
|
||||||
var config Array<Squad> SquadsSpecial;
|
|
||||||
var config Array<Squad> SquadsEvent;
|
|
||||||
|
|
||||||
public static function InitConfig(KFGI_Access KFGIA)
|
|
||||||
{
|
|
||||||
local KFAIWaveInfo KFAIWI;
|
|
||||||
local KFAISpawnSquad KFAISS;
|
|
||||||
local AISquadElement AISE;
|
|
||||||
local Squad S;
|
|
||||||
local Unit U;
|
|
||||||
|
|
||||||
KFAIWI = default.DefSpawnManager.default.DifficultyWaveSettings[default.Difficulty].Waves[default.Wave];
|
|
||||||
|
|
||||||
default.bRecycleWave = KFAIWI.bRecycleWave;
|
|
||||||
default.MaxAI = KFAIWI.MaxAI;
|
|
||||||
|
|
||||||
default.Squads.Length = 0;
|
|
||||||
foreach KFAIWI.Squads(KFAISS)
|
|
||||||
{
|
|
||||||
S.MinVolumeType = KFAISS.MinVolumeType;
|
|
||||||
foreach KFAISS.MonsterList(AISE)
|
|
||||||
{
|
|
||||||
U.ZedClass = GetPawnClassString(KFGIA, AISE);
|
|
||||||
U.Num = AISE.Num;
|
|
||||||
S.Units.AddItem(U);
|
|
||||||
}
|
|
||||||
default.Squads.AddItem(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
default.SquadsSpecial.Length = 0;
|
|
||||||
foreach KFAIWI.SpecialSquads(KFAISS)
|
|
||||||
{
|
|
||||||
S.MinVolumeType = KFAISS.MinVolumeType;
|
|
||||||
foreach KFAISS.MonsterList(AISE)
|
|
||||||
{
|
|
||||||
U.ZedClass = GetPawnClassString(KFGIA, AISE);
|
|
||||||
U.Num = AISE.Num;
|
|
||||||
S.Units.AddItem(U);
|
|
||||||
}
|
|
||||||
default.SquadsSpecial.AddItem(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
default.SquadsEvent.Length = 0;
|
|
||||||
foreach KFAIWI.EventSquads(KFAISS)
|
|
||||||
{
|
|
||||||
S.MinVolumeType = KFAISS.MinVolumeType;
|
|
||||||
foreach KFAISS.MonsterList(AISE)
|
|
||||||
{
|
|
||||||
U.ZedClass = GetPawnClassString(KFGIA, AISE);
|
|
||||||
U.Num = AISE.Num;
|
|
||||||
S.Units.AddItem(U);
|
|
||||||
}
|
|
||||||
default.SquadsEvent.AddItem(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticSaveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function String GetPawnClassString(KFGI_Access KFGIA, AISquadElement AISE)
|
|
||||||
{
|
|
||||||
local class<KFPawn_Monster> KFPMC;
|
|
||||||
|
|
||||||
KFPMC = KFGIA.AITypePawn(AISE.Type);
|
|
||||||
if (KFPMC == None)
|
|
||||||
KFPMC = AISE.CustomClass;
|
|
||||||
|
|
||||||
return "KFGameContent." $ String(KFPMC);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function AIWaveInfo Load(E_LogLevel LogLevel, KFGI_Access KFGIA)
|
|
||||||
{
|
|
||||||
local class<KFPawn_Monster> KFPMC;
|
|
||||||
local AIWaveInfo AIWI;
|
|
||||||
local AISpawnSquad AISS;
|
|
||||||
local S_AISquadElement AISE;
|
|
||||||
local Squad S;
|
|
||||||
local Unit U;
|
|
||||||
|
|
||||||
AIWI = new class'AIWaveInfo';
|
|
||||||
|
|
||||||
AIWI.bRecycleWave = default.bRecycleWave;
|
|
||||||
AIWI.MaxAI = default.MaxAI;
|
|
||||||
|
|
||||||
foreach default.Squads(S)
|
|
||||||
{
|
|
||||||
AISS = new class'AISpawnSquad';
|
|
||||||
AISS.MinVolumeType = S.MinVolumeType;
|
|
||||||
foreach S.Units(U)
|
|
||||||
{
|
|
||||||
KFPMC = class<KFPawn_Monster>(DynamicLoadObject(U.ZedClass, class'Class'));
|
|
||||||
if (KFPMC == None)
|
|
||||||
{
|
|
||||||
`ZS_Warn("Can't load zed class:" @ U.ZedClass);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!KFGIA.IsOriginalAI(KFPMC, AISE.Type))
|
|
||||||
AISE.CustomClass = KFPMC;
|
|
||||||
|
|
||||||
AISE.Num = AISE.Num;
|
|
||||||
|
|
||||||
AISS.MonsterList.AddItem(AISE);
|
|
||||||
}
|
|
||||||
AIWI.Squads.AddItem(AISS);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach default.SquadsSpecial(S)
|
|
||||||
{
|
|
||||||
AISS = new class'AISpawnSquad';
|
|
||||||
AISS.MinVolumeType = S.MinVolumeType;
|
|
||||||
foreach S.Units(U)
|
|
||||||
{
|
|
||||||
KFPMC = class<KFPawn_Monster>(DynamicLoadObject(U.ZedClass, class'Class'));
|
|
||||||
if (KFPMC == None)
|
|
||||||
{
|
|
||||||
`ZS_Warn("Can't load zed class:" @ U.ZedClass);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!KFGIA.IsOriginalAI(KFPMC, AISE.Type))
|
|
||||||
AISE.CustomClass = KFPMC;
|
|
||||||
|
|
||||||
AISE.Num = AISE.Num;
|
|
||||||
|
|
||||||
AISS.MonsterList.AddItem(AISE);
|
|
||||||
}
|
|
||||||
AIWI.SpecialSquads.AddItem(AISS);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach default.SquadsEvent(S)
|
|
||||||
{
|
|
||||||
AISS = new class'AISpawnSquad';
|
|
||||||
AISS.MinVolumeType = S.MinVolumeType;
|
|
||||||
foreach S.Units(U)
|
|
||||||
{
|
|
||||||
KFPMC = class<KFPawn_Monster>(DynamicLoadObject(U.ZedClass, class'Class'));
|
|
||||||
if (KFPMC == None)
|
|
||||||
{
|
|
||||||
`ZS_Warn("Can't load zed class:" @ U.ZedClass);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!KFGIA.IsOriginalAI(KFPMC, AISE.Type))
|
|
||||||
AISE.CustomClass = KFPMC;
|
|
||||||
|
|
||||||
AISE.Num = AISE.Num;
|
|
||||||
|
|
||||||
AISS.MonsterList.AddItem(AISE);
|
|
||||||
}
|
|
||||||
AIWI.EventSquads.AddItem(AISS);
|
|
||||||
}
|
|
||||||
|
|
||||||
return AIWI;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
DefSpawnManager = class'KFAISpawnManager'
|
|
||||||
Difficulty = 255
|
|
||||||
Wave = 255
|
|
||||||
}
|
|
@ -1,6 +1,39 @@
|
|||||||
class KFGI_Access extends Object
|
class KFGI_Access extends Object
|
||||||
within KFGameInfo;
|
within KFGameInfo;
|
||||||
|
|
||||||
|
public function Array<class<KFPawn_Monster> > GetAIClassList()
|
||||||
|
{
|
||||||
|
local Array<class<KFPawn_Monster> > RV;
|
||||||
|
local class<KFPawn_Monster> KFPMC;
|
||||||
|
|
||||||
|
foreach AIClassList(KFPMC)
|
||||||
|
RV.AddItem(KFPMC);
|
||||||
|
|
||||||
|
return RV;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Array<class<KFPawn_Monster> > GetNonSpawnAIClassList()
|
||||||
|
{
|
||||||
|
local Array<class<KFPawn_Monster> > RV;
|
||||||
|
local class<KFPawn_Monster> KFPMC;
|
||||||
|
|
||||||
|
foreach NonSpawnAIClassList(KFPMC)
|
||||||
|
RV.AddItem(KFPMC);
|
||||||
|
|
||||||
|
return RV;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Array<class<KFPawn_Monster> > GetAIBossClassList()
|
||||||
|
{
|
||||||
|
local Array<class<KFPawn_Monster> > RV;
|
||||||
|
local class<KFPawn_Monster> KFPMC;
|
||||||
|
|
||||||
|
foreach AIBossClassList(KFPMC)
|
||||||
|
RV.AddItem(KFPMC);
|
||||||
|
|
||||||
|
return RV;
|
||||||
|
}
|
||||||
|
|
||||||
public function bool IsCustomZed(class<KFPawn_Monster> KFPM)
|
public function bool IsCustomZed(class<KFPawn_Monster> KFPM)
|
||||||
{
|
{
|
||||||
if (AIClassList.Find(KFPM) != INDEX_NONE) return false;
|
if (AIClassList.Find(KFPM) != INDEX_NONE) return false;
|
||||||
@ -9,7 +42,6 @@ public function bool IsCustomZed(class<KFPawn_Monster> KFPM)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARN: <optional out> - can it work? need check
|
|
||||||
public function bool IsOriginalAI(class<KFPawn_Monster> KFPM, optional out EAIType AIType)
|
public function bool IsOriginalAI(class<KFPawn_Monster> KFPM, optional out EAIType AIType)
|
||||||
{
|
{
|
||||||
local int Type;
|
local int Type;
|
||||||
|
@ -1,32 +1,44 @@
|
|||||||
class Config_Spawner extends Object
|
class Spawn extends Object
|
||||||
dependson(ZedSpawner)
|
dependson(ZedSpawner)
|
||||||
config(ZedSpawner);
|
config(ZedSpawner);
|
||||||
|
|
||||||
var config bool bCyclicalSpawn;
|
var public config bool bCyclicalSpawn;
|
||||||
var config bool bShadowSpawn;
|
var public config bool bShadowSpawn;
|
||||||
|
var public config float ZedTotalMultiplier;
|
||||||
|
var public config float SpawnTotalPlayerMultiplier;
|
||||||
|
var public config float SpawnTotalCycleMultiplier;
|
||||||
|
var public config float SingleSpawnLimitMultiplier;
|
||||||
|
var public config float SingleSpawnLimitPlayerMultiplier;
|
||||||
|
var public config float SingleSpawnLimitCycleMultiplier;
|
||||||
|
var public config int AliveSpawnLimit;
|
||||||
|
|
||||||
var config float ZedTotalMultiplier;
|
public static function InitConfig(int Version, int LatestVersion)
|
||||||
var config float SpawnTotalPlayerMultiplier;
|
|
||||||
var config float SpawnTotalCycleMultiplier;
|
|
||||||
|
|
||||||
var config float SingleSpawnLimitMultiplier;
|
|
||||||
var config float SingleSpawnLimitPlayerMultiplier;
|
|
||||||
var config float SingleSpawnLimitCycleMultiplier;
|
|
||||||
|
|
||||||
var config int AliveSpawnLimit;
|
|
||||||
|
|
||||||
public static function InitConfig()
|
|
||||||
{
|
{
|
||||||
default.bCyclicalSpawn = true;
|
switch (Version)
|
||||||
default.bShadowSpawn = true;
|
{
|
||||||
default.ZedTotalMultiplier = 1.0;
|
case `NO_CONFIG:
|
||||||
default.SpawnTotalPlayerMultiplier = 0.75;
|
ApplyDefault();
|
||||||
default.SpawnTotalCycleMultiplier = 0.75;
|
|
||||||
default.SingleSpawnLimitPlayerMultiplier = 0.75;
|
default: break;
|
||||||
default.SingleSpawnLimitCycleMultiplier = 0.75;
|
}
|
||||||
default.AliveSpawnLimit = 0;
|
|
||||||
|
if (LatestVersion != Version)
|
||||||
|
{
|
||||||
|
StaticSaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StaticSaveConfig();
|
private static function ApplyDefault()
|
||||||
|
{
|
||||||
|
default.bCyclicalSpawn = true;
|
||||||
|
default.bShadowSpawn = true;
|
||||||
|
default.ZedTotalMultiplier = 1.0;
|
||||||
|
default.SpawnTotalPlayerMultiplier = 0.75;
|
||||||
|
default.SpawnTotalCycleMultiplier = 0.75;
|
||||||
|
default.SingleSpawnLimitMultiplier = 1.0;
|
||||||
|
default.SingleSpawnLimitPlayerMultiplier = 0.75;
|
||||||
|
default.SingleSpawnLimitCycleMultiplier = 0.75;
|
||||||
|
default.AliveSpawnLimit = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function bool Load(E_LogLevel LogLevel)
|
public static function bool Load(E_LogLevel LogLevel)
|
@ -1,4 +1,4 @@
|
|||||||
class Config_SpawnListBossWaves extends Object
|
class SpawnListBossWaves extends Object
|
||||||
dependson(ZedSpawner)
|
dependson(ZedSpawner)
|
||||||
config(ZedSpawner);
|
config(ZedSpawner);
|
||||||
|
|
||||||
@ -13,31 +13,47 @@ struct S_SpawnEntryCfg
|
|||||||
var bool bSpawnAtPlayerStart;
|
var bool bSpawnAtPlayerStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
var config bool bStopRegularSpawn;
|
var public config bool bStopRegularSpawn;
|
||||||
var config Array<S_SpawnEntryCfg> Spawn;
|
var private config Array<S_SpawnEntryCfg> Spawn;
|
||||||
|
|
||||||
public static function InitConfig()
|
public static function InitConfig(int Version, int LatestVersion, KFGI_Access KFGIA)
|
||||||
{
|
{
|
||||||
local S_SpawnEntryCfg SpawnEntry;
|
switch (Version)
|
||||||
|
{
|
||||||
|
case `NO_CONFIG:
|
||||||
|
ApplyDefault(KFGIA);
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
default.bStopRegularSpawn = true;
|
if (LatestVersion != Version)
|
||||||
|
{
|
||||||
|
StaticSaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function ApplyDefault(KFGI_Access KFGIA)
|
||||||
|
{
|
||||||
|
local S_SpawnEntryCfg SpawnEntry;
|
||||||
|
local Array<class<KFPawn_Monster> > KFPM_Bosses;
|
||||||
|
local class<KFPawn_Monster> KFPMC;
|
||||||
|
|
||||||
default.Spawn.Length = 0;
|
default.Spawn.Length = 0;
|
||||||
|
|
||||||
SpawnEntry.BossClass = "KFGameContent.KFPawn_ZedFleshpoundKing";
|
default.bStopRegularSpawn = true;
|
||||||
|
default.Spawn.Length = 0;
|
||||||
SpawnEntry.ZedClass = "SomePackage.SomeClass";
|
SpawnEntry.ZedClass = "SomePackage.SomeClass";
|
||||||
SpawnEntry.SpawnCountBase = 2;
|
SpawnEntry.SpawnCountBase = 2;
|
||||||
SpawnEntry.SingleSpawnLimit = 1;
|
SpawnEntry.SingleSpawnLimit = 1;
|
||||||
SpawnEntry.Delay = 60;
|
SpawnEntry.Delay = 30;
|
||||||
SpawnEntry.Probability = 100;
|
SpawnEntry.Probability = 100;
|
||||||
SpawnEntry.bSpawnAtPlayerStart = false;
|
SpawnEntry.bSpawnAtPlayerStart = false;
|
||||||
default.Spawn.AddItem(SpawnEntry);
|
KFPM_Bosses = KFGIA.GetAIBossClassList();
|
||||||
|
foreach KFPM_Bosses(KFPMC)
|
||||||
// TODO:
|
{
|
||||||
//SpawnEntry.BossClass = "KFGameContent.KFPawn_ZedFleshpoundKing";
|
SpawnEntry.BossClass = "KFGameContent." $ String(KFPMC);
|
||||||
//default.Spawn.AddItem(SpawnEntry);
|
default.Spawn.AddItem(SpawnEntry);
|
||||||
|
}
|
||||||
StaticSaveConfig();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
||||||
@ -47,8 +63,9 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
local S_SpawnEntry SpawnEntry;
|
local S_SpawnEntry SpawnEntry;
|
||||||
local int Line;
|
local int Line;
|
||||||
local bool Errors;
|
local bool Errors;
|
||||||
|
local int Loaded;
|
||||||
|
|
||||||
`ZS_Info("Load boss waves spawn list:");
|
`ZS_Info("Load boss waves spawn list...");
|
||||||
foreach default.Spawn(SpawnEntryCfg, Line)
|
foreach default.Spawn(SpawnEntryCfg, Line)
|
||||||
{
|
{
|
||||||
Errors = false;
|
Errors = false;
|
||||||
@ -101,11 +118,21 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
|
|
||||||
if (!Errors)
|
if (!Errors)
|
||||||
{
|
{
|
||||||
|
Loaded++;
|
||||||
SpawnList.AddItem(SpawnEntry);
|
SpawnList.AddItem(SpawnEntry);
|
||||||
`ZS_Info("[" $ Line + 1 $ "]" @ "Loaded successfully:" @ SpawnEntryCfg.BossClass @ SpawnEntryCfg.ZedClass);
|
`ZS_Debug("[" $ Line + 1 $ "]" @ "Loaded successfully: (" $ SpawnEntryCfg.BossClass $ ")" @ SpawnEntryCfg.ZedClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Loaded == default.Spawn.Length)
|
||||||
|
{
|
||||||
|
`ZS_Info("Boss spawn list loaded successfully");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
`ZS_Info("Boss spawn list: loaded" @ Loaded @ "of" @ default.Spawn.Length @ "entries");
|
||||||
|
}
|
||||||
|
|
||||||
return SpawnList;
|
return SpawnList;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
class Config_SpawnListRegular extends Object
|
class SpawnListRegular extends Object
|
||||||
dependson(ZedSpawner)
|
dependson(ZedSpawner)
|
||||||
config(ZedSpawner);
|
config(ZedSpawner);
|
||||||
|
|
||||||
@ -14,35 +14,47 @@ struct S_SpawnEntryCfg
|
|||||||
var bool bSpawnAtPlayerStart;
|
var bool bSpawnAtPlayerStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
var config Array<S_SpawnEntryCfg> Spawn;
|
var public config Array<S_SpawnEntryCfg> Spawn;
|
||||||
|
|
||||||
public static function InitConfig()
|
public static function InitConfig(int Version, int LatestVersion, KFGI_Access KFGIA)
|
||||||
{
|
{
|
||||||
local S_SpawnEntryCfg SpawnEntry;
|
switch (Version)
|
||||||
|
{
|
||||||
|
case `NO_CONFIG:
|
||||||
|
ApplyDefault(KFGIA);
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LatestVersion != Version)
|
||||||
|
{
|
||||||
|
StaticSaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function ApplyDefault(KFGI_Access KFGIA)
|
||||||
|
{
|
||||||
|
local S_SpawnEntryCfg SpawnEntry;
|
||||||
|
local Array<class<KFPawn_Monster> > KFPM_Zeds;
|
||||||
|
local class<KFPawn_Monster> KFPMC;
|
||||||
|
|
||||||
default.Spawn.Length = 0;
|
default.Spawn.Length = 0;
|
||||||
|
|
||||||
SpawnEntry.Wave = 1;
|
SpawnEntry.Wave = 0;
|
||||||
SpawnEntry.ZedClass = "SomePackage.SomeZedClass1";
|
|
||||||
SpawnEntry.SpawnCountBase = 2;
|
|
||||||
SpawnEntry.SingleSpawnLimit = 1;
|
|
||||||
SpawnEntry.RelativeStart = 0;
|
|
||||||
SpawnEntry.Delay = 60;
|
|
||||||
SpawnEntry.Probability = 100;
|
|
||||||
SpawnEntry.bSpawnAtPlayerStart = false;
|
|
||||||
default.Spawn.AddItem(SpawnEntry);
|
|
||||||
|
|
||||||
SpawnEntry.Wave = 2;
|
|
||||||
SpawnEntry.ZedClass = "SomePackage.SomeZedClass2";
|
|
||||||
SpawnEntry.SpawnCountBase = 2;
|
SpawnEntry.SpawnCountBase = 2;
|
||||||
SpawnEntry.SingleSpawnLimit = 1;
|
SpawnEntry.SingleSpawnLimit = 1;
|
||||||
SpawnEntry.RelativeStart = 25;
|
SpawnEntry.RelativeStart = 25;
|
||||||
SpawnEntry.Delay = 30;
|
SpawnEntry.Delay = 60;
|
||||||
SpawnEntry.Probability = 50;
|
SpawnEntry.Probability = 100;
|
||||||
SpawnEntry.bSpawnAtPlayerStart = false;
|
SpawnEntry.bSpawnAtPlayerStart = false;
|
||||||
default.Spawn.AddItem(SpawnEntry);
|
|
||||||
|
|
||||||
StaticSaveConfig();
|
KFPM_Zeds = KFGIA.GetAIClassList();
|
||||||
|
foreach KFPM_Zeds(KFPMC)
|
||||||
|
{
|
||||||
|
++SpawnEntry.Wave;
|
||||||
|
SpawnEntry.ZedClass = "KFGameContent." $ String(KFPMC);
|
||||||
|
default.Spawn.AddItem(SpawnEntry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
||||||
@ -52,6 +64,7 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
local S_SpawnEntry SpawnEntry;
|
local S_SpawnEntry SpawnEntry;
|
||||||
local int Line;
|
local int Line;
|
||||||
local bool Errors;
|
local bool Errors;
|
||||||
|
local int Loaded;
|
||||||
|
|
||||||
`ZS_Info("Load spawn list:");
|
`ZS_Info("Load spawn list:");
|
||||||
foreach default.Spawn(SpawnEntryCfg, Line)
|
foreach default.Spawn(SpawnEntryCfg, Line)
|
||||||
@ -111,11 +124,21 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
|
|
||||||
if (!Errors)
|
if (!Errors)
|
||||||
{
|
{
|
||||||
|
Loaded++;
|
||||||
SpawnList.AddItem(SpawnEntry);
|
SpawnList.AddItem(SpawnEntry);
|
||||||
`ZS_Info("[" $ Line + 1 $ "]" @ "Loaded successfully:" @ SpawnEntryCfg.Wave @ SpawnEntryCfg.ZedClass);
|
`ZS_Debug("[" $ Line + 1 $ "]" @ "Loaded successfully: (w" $ SpawnEntryCfg.Wave $ ")" @ SpawnEntryCfg.ZedClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Loaded == default.Spawn.Length)
|
||||||
|
{
|
||||||
|
`ZS_Info("Regular spawn list loaded successfully");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
`ZS_Info("Regular spawn list: loaded" @ Loaded @ "of" @ default.Spawn.Length @ "entries");
|
||||||
|
}
|
||||||
|
|
||||||
return SpawnList;
|
return SpawnList;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
class Config_SpawnListSpecialWaves extends Object
|
class SpawnListSpecialWaves extends Object
|
||||||
dependson(ZedSpawner)
|
dependson(ZedSpawner)
|
||||||
config(ZedSpawner);
|
config(ZedSpawner);
|
||||||
|
|
||||||
@ -14,18 +14,32 @@ struct S_SpawnEntryCfg
|
|||||||
var bool bSpawnAtPlayerStart;
|
var bool bSpawnAtPlayerStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
var config bool bStopRegularSpawn;
|
var public config bool bStopRegularSpawn;
|
||||||
var config Array<S_SpawnEntryCfg> Spawn;
|
var private config Array<S_SpawnEntryCfg> Spawn;
|
||||||
|
|
||||||
public static function InitConfig()
|
public static function InitConfig(int Version, int LatestVersion)
|
||||||
|
{
|
||||||
|
switch (Version)
|
||||||
|
{
|
||||||
|
case `NO_CONFIG:
|
||||||
|
ApplyDefault();
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LatestVersion != Version)
|
||||||
|
{
|
||||||
|
StaticSaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function ApplyDefault()
|
||||||
{
|
{
|
||||||
local S_SpawnEntryCfg SpawnEntry;
|
local S_SpawnEntryCfg SpawnEntry;
|
||||||
|
local EAIType AIType;
|
||||||
|
|
||||||
default.bStopRegularSpawn = true;
|
default.bStopRegularSpawn = true;
|
||||||
|
|
||||||
default.Spawn.Length = 0;
|
default.Spawn.Length = 0;
|
||||||
|
|
||||||
SpawnEntry.Wave = AT_Husk;
|
|
||||||
SpawnEntry.ZedClass = "SomePackage.SomeClass";
|
SpawnEntry.ZedClass = "SomePackage.SomeClass";
|
||||||
SpawnEntry.SpawnCountBase = 2;
|
SpawnEntry.SpawnCountBase = 2;
|
||||||
SpawnEntry.SingleSpawnLimit = 1;
|
SpawnEntry.SingleSpawnLimit = 1;
|
||||||
@ -33,9 +47,11 @@ public static function InitConfig()
|
|||||||
SpawnEntry.Delay = 60;
|
SpawnEntry.Delay = 60;
|
||||||
SpawnEntry.Probability = 100;
|
SpawnEntry.Probability = 100;
|
||||||
SpawnEntry.bSpawnAtPlayerStart = false;
|
SpawnEntry.bSpawnAtPlayerStart = false;
|
||||||
default.Spawn.AddItem(SpawnEntry);
|
foreach class'KFGameInfo_Endless'.default.SpecialWaveTypes(AIType)
|
||||||
|
{
|
||||||
StaticSaveConfig();
|
SpawnEntry.Wave = AIType;
|
||||||
|
default.Spawn.AddItem(SpawnEntry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Array<S_SpawnEntry> Load(KFGameInfo_Endless KFGIE, E_LogLevel LogLevel)
|
public static function Array<S_SpawnEntry> Load(KFGameInfo_Endless KFGIE, E_LogLevel LogLevel)
|
||||||
@ -45,6 +61,7 @@ public static function Array<S_SpawnEntry> Load(KFGameInfo_Endless KFGIE, E_LogL
|
|||||||
local S_SpawnEntry SpawnEntry;
|
local S_SpawnEntry SpawnEntry;
|
||||||
local int Line;
|
local int Line;
|
||||||
local bool Errors;
|
local bool Errors;
|
||||||
|
local int Loaded;
|
||||||
|
|
||||||
if (KFGIE == None)
|
if (KFGIE == None)
|
||||||
{
|
{
|
||||||
@ -110,11 +127,21 @@ public static function Array<S_SpawnEntry> Load(KFGameInfo_Endless KFGIE, E_LogL
|
|||||||
|
|
||||||
if (!Errors)
|
if (!Errors)
|
||||||
{
|
{
|
||||||
|
Loaded++;
|
||||||
SpawnList.AddItem(SpawnEntry);
|
SpawnList.AddItem(SpawnEntry);
|
||||||
`ZS_Info("[" $ Line + 1 $ "]" @ "Loaded successfully:" @ SpawnEntryCfg.Wave @ SpawnEntryCfg.ZedClass);
|
`ZS_Debug("[" $ Line + 1 $ "]" @ "Loaded successfully: (" $ SpawnEntryCfg.Wave $ ")" @ SpawnEntryCfg.ZedClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Loaded == default.Spawn.Length)
|
||||||
|
{
|
||||||
|
`ZS_Info("Special spawn list loaded successfully");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
`ZS_Info("Special spawn list: loaded" @ Loaded @ "of" @ default.Spawn.Length @ "entries");
|
||||||
|
}
|
||||||
|
|
||||||
return SpawnList;
|
return SpawnList;
|
||||||
}
|
}
|
||||||
|
|
@ -1,89 +1,78 @@
|
|||||||
class ZedSpawner extends Info
|
class ZedSpawner extends Info
|
||||||
config(ZedSpawner);
|
config(ZedSpawner);
|
||||||
|
|
||||||
|
const LatestVersion = 1;
|
||||||
|
|
||||||
const dt = 1;
|
const dt = 1;
|
||||||
|
|
||||||
const CfgSpawn = class'Config_Spawner';
|
const CfgSpawn = class'Spawn';
|
||||||
const CfgSpawnListR = class'Config_SpawnListRegular';
|
const CfgSpawnListRW = class'SpawnListRegular';
|
||||||
const CfgSpawnListBW = class'Config_SpawnListBossWaves';
|
const CfgSpawnListBW = class'SpawnListBossWaves';
|
||||||
const CfgSpawnListSW = class'Config_SpawnListSpecialWaves';
|
const CfgSpawnListSW = class'SpawnListSpecialWaves';
|
||||||
const CfgSpawnManagerE = class'Config_SpawnManager_Endless';
|
|
||||||
const CfgSpawnManagerS = class'Config_SpawnManager_Short';
|
|
||||||
const CfgSpawnManagerN = class'Config_SpawnManager_Normal';
|
|
||||||
const CfgSpawnManagerL = class'Config_SpawnManager_Long';
|
|
||||||
|
|
||||||
const SpawnManagerS = class'AISpawnManager_Short';
|
enum E_LogLevel
|
||||||
const SpawnManagerN = class'AISpawnManager_Normal';
|
{
|
||||||
const SpawnManagerL = class'AISpawnManager_Long';
|
LL_WrongLevel,
|
||||||
const SpawnManagerE = class'AISpawnManager_Endless';
|
LL_Fatal,
|
||||||
|
LL_Error,
|
||||||
|
LL_Warning,
|
||||||
|
LL_Info,
|
||||||
|
LL_Debug,
|
||||||
|
LL_Trace,
|
||||||
|
LL_All
|
||||||
|
};
|
||||||
|
|
||||||
struct S_SpawnEntry
|
struct S_SpawnEntry
|
||||||
{
|
{
|
||||||
var class<KFPawn_Monster> BossClass;
|
var class<KFPawn_Monster> BossClass;
|
||||||
var class<KFPawn_Monster> ZedClass;
|
var class<KFPawn_Monster> ZedClass;
|
||||||
var int Wave;
|
var byte Wave;
|
||||||
var int SpawnCountBase;
|
var int SpawnCountBase;
|
||||||
var int SingleSpawnLimitDefault;
|
var int SingleSpawnLimitDefault;
|
||||||
var int SingleSpawnLimit;
|
var int SingleSpawnLimit;
|
||||||
var float Probability;
|
var float Probability;
|
||||||
var float RelativeStartDefault;
|
var float RelativeStartDefault;
|
||||||
var float RelativeStart;
|
var float RelativeStart;
|
||||||
var int DelayDefault;
|
var int DelayDefault;
|
||||||
var int Delay;
|
var int Delay;
|
||||||
var int SpawnsLeft;
|
var int SpawnsLeft;
|
||||||
var int SpawnsTotal;
|
var int SpawnsTotal;
|
||||||
var bool SpawnAtPlayerStart;
|
var bool SpawnAtPlayerStart;
|
||||||
|
var bool ForceSpawn;
|
||||||
|
var String ZedNameFiller;
|
||||||
};
|
};
|
||||||
|
|
||||||
var config bool bConfigInitialized;
|
var private config int Version;
|
||||||
var config E_LogLevel LogLevel;
|
var private config E_LogLevel LogLevel;
|
||||||
|
|
||||||
var private Array<S_SpawnEntry> SpawnListR;
|
var private Array<S_SpawnEntry> SpawnListRW;
|
||||||
var private Array<S_SpawnEntry> SpawnListBW;
|
var private Array<S_SpawnEntry> SpawnListBW;
|
||||||
var private Array<S_SpawnEntry> SpawnListSW;
|
var private Array<S_SpawnEntry> SpawnListSW;
|
||||||
|
var private Array<S_SpawnEntry> SpawnListCurrent;
|
||||||
|
|
||||||
|
var private bool NoFreeSpawnSlots;
|
||||||
|
var private bool UseRegularSpawnList;
|
||||||
|
var private bool UseBossSpawnList;
|
||||||
|
var private bool UseSpecialSpawnList;
|
||||||
|
|
||||||
var private KFGameInfo_Survival KFGIS;
|
var private KFGameInfo_Survival KFGIS;
|
||||||
var private KFGameInfo_Endless KFGIE;
|
var private KFGameInfo_Endless KFGIE;
|
||||||
|
var private KFGI_Access KFGIA;
|
||||||
var private KFGI_Access KFGIA;
|
|
||||||
|
|
||||||
var private int CurrentWave;
|
var private int CurrentWave;
|
||||||
|
var private int SpecialWave;
|
||||||
var private int CurrentCycle;
|
var private int CurrentCycle;
|
||||||
var private int CycleWaveShift;
|
var private int CycleWaveShift;
|
||||||
var private int CycleWaveSize;
|
var private int CycleWaveSize;
|
||||||
|
|
||||||
var private int WaveTotalAI;
|
var private int WaveTotalAI;
|
||||||
var private class<KFPawn_Monster> CurrentBossClass;
|
|
||||||
var private int SpecialWave;
|
|
||||||
|
|
||||||
var private String SpawnTimerLastMessage;
|
var private class<KFPawn_Monster> CurrentBossClass;
|
||||||
|
|
||||||
var private Array<class<KFPawn_Monster> > BossClassCache;
|
|
||||||
var private Array<class<KFPawn_Monster> > CustomZeds;
|
var private Array<class<KFPawn_Monster> > CustomZeds;
|
||||||
|
|
||||||
delegate bool WaveCondition(S_SpawnEntry SE);
|
var private bool SpawnActive;
|
||||||
|
var private String SpawnListsComment;
|
||||||
|
|
||||||
event PreBeginPlay()
|
public event PreBeginPlay()
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
Super.PreBeginPlay();
|
|
||||||
|
|
||||||
PreInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
event PostBeginPlay()
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
if (bPendingDelete) return;
|
|
||||||
|
|
||||||
Super.PostBeginPlay();
|
|
||||||
|
|
||||||
PostInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function PreInit()
|
|
||||||
{
|
{
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
@ -94,52 +83,66 @@ private function PreInit()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bConfigInitialized)
|
Super.PreBeginPlay();
|
||||||
{
|
}
|
||||||
bConfigInitialized = true;
|
|
||||||
LogLevel = LL_Info;
|
|
||||||
SaveConfig();
|
|
||||||
CfgSpawn.static.InitConfig();
|
|
||||||
CfgSpawnListR.static.InitConfig();
|
|
||||||
CfgSpawnListBW.static.InitConfig();
|
|
||||||
CfgSpawnListSW.static.InitConfig();
|
|
||||||
CfgSpawnManagerS.static.InitConfig();
|
|
||||||
CfgSpawnManagerN.static.InitConfig();
|
|
||||||
CfgSpawnManagerL.static.InitConfig();
|
|
||||||
CfgSpawnManagerE.static.InitConfig();
|
|
||||||
`ZS_Info("Config initialized.");
|
|
||||||
}
|
|
||||||
|
|
||||||
CfgSpawnManagerS.static.InitConfig();
|
|
||||||
CfgSpawnManagerN.static.InitConfig();
|
|
||||||
CfgSpawnManagerL.static.InitConfig();
|
|
||||||
CfgSpawnManagerE.static.InitConfig();
|
|
||||||
|
|
||||||
if (LogLevel == LL_WrongLevel)
|
public event PostBeginPlay()
|
||||||
|
{
|
||||||
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
|
if (bPendingDelete) return;
|
||||||
|
|
||||||
|
Super.PostBeginPlay();
|
||||||
|
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function InitConfig()
|
||||||
|
{
|
||||||
|
if (Version == `NO_CONFIG)
|
||||||
{
|
{
|
||||||
LogLevel = LL_Info;
|
LogLevel = LL_Info;
|
||||||
`ZS_Warn("Wrong 'LogLevel', return to default value");
|
|
||||||
SaveConfig();
|
SaveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
`ZS_Log("LogLevel:" @ LogLevel);
|
CfgSpawn.static.InitConfig(Version, LatestVersion);
|
||||||
|
CfgSpawnListRW.static.InitConfig(Version, LatestVersion, KFGIA);
|
||||||
|
CfgSpawnListBW.static.InitConfig(Version, LatestVersion, KFGIA);
|
||||||
|
CfgSpawnListSW.static.InitConfig(Version, LatestVersion);
|
||||||
|
|
||||||
if (!CfgSpawn.static.Load(LogLevel))
|
switch (Version)
|
||||||
{
|
{
|
||||||
`ZS_Fatal("Wrong settings, Destroy...");
|
case `NO_CONFIG:
|
||||||
Destroy();
|
`ZS_Info("Config created");
|
||||||
return;
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function PostInit()
|
private function Init()
|
||||||
{
|
{
|
||||||
local S_SpawnEntry SE;
|
local S_SpawnEntry SE;
|
||||||
local bool NeedInitSM;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
CurrentWave = INDEX_NONE;
|
|
||||||
KFGIS = KFGameInfo_Survival(WorldInfo.Game);
|
KFGIS = KFGameInfo_Survival(WorldInfo.Game);
|
||||||
if (KFGIS == None)
|
if (KFGIS == None)
|
||||||
{
|
{
|
||||||
@ -151,76 +154,61 @@ private function PostInit()
|
|||||||
KFGIA = new(KFGIS) class'KFGI_Access';
|
KFGIA = new(KFGIS) class'KFGI_Access';
|
||||||
KFGIE = KFGameInfo_Endless(KFGIS);
|
KFGIE = KFGameInfo_Endless(KFGIS);
|
||||||
|
|
||||||
SpawnListR = CfgSpawnListR.static.Load(LogLevel);
|
InitConfig();
|
||||||
|
|
||||||
|
if (LogLevel == LL_WrongLevel)
|
||||||
|
{
|
||||||
|
LogLevel = LL_Info;
|
||||||
|
`ZS_Warn("Wrong 'LogLevel', return to default value");
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
`ZS_Log("LogLevel:" @ LogLevel);
|
||||||
|
|
||||||
|
if (!CfgSpawn.static.Load(LogLevel))
|
||||||
|
{
|
||||||
|
`ZS_Fatal("Wrong settings, Destroy...");
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnListRW = CfgSpawnListRW.static.Load(LogLevel);
|
||||||
SpawnListBW = CfgSpawnListBW.static.Load(LogLevel);
|
SpawnListBW = CfgSpawnListBW.static.Load(LogLevel);
|
||||||
SpawnListSW = CfgSpawnListSW.static.Load(KFGIE, LogLevel);
|
SpawnListSW = CfgSpawnListSW.static.Load(KFGIE, LogLevel);
|
||||||
|
|
||||||
CfgSpawnManagerE.static.Load(LogLevel);
|
CurrentWave = INDEX_NONE;
|
||||||
CfgSpawnManagerS.static.Load(LogLevel);
|
|
||||||
CfgSpawnManagerN.static.Load(LogLevel);
|
|
||||||
CfgSpawnManagerL.static.Load(LogLevel);
|
|
||||||
|
|
||||||
SpecialWave = INDEX_NONE;
|
SpecialWave = INDEX_NONE;
|
||||||
CurrentCycle = 1;
|
CurrentCycle = 1;
|
||||||
CycleWaveSize = 0;
|
|
||||||
CycleWaveShift = MaxInt;
|
|
||||||
foreach SpawnListR(SE)
|
|
||||||
{
|
|
||||||
CycleWaveShift = Min(CycleWaveShift, SE.Wave);
|
|
||||||
CycleWaveSize = Max(CycleWaveSize, SE.Wave);
|
|
||||||
}
|
|
||||||
CycleWaveSize = CycleWaveSize - CycleWaveShift + 1;
|
|
||||||
|
|
||||||
foreach SpawnListBW(SE)
|
if (CfgSpawn.default.bCyclicalSpawn)
|
||||||
if (BossClassCache.Find(SE.BossClass) == INDEX_NONE)
|
|
||||||
BossClassCache.AddItem(SE.BossClass);
|
|
||||||
|
|
||||||
if (true)
|
|
||||||
{
|
{
|
||||||
NeedInitSM = (KFGIS.SpawnManager != None);
|
CycleWaveSize = 0;
|
||||||
KFGIS.SpawnManagerClasses.Length = 0;
|
CycleWaveShift = MaxInt;
|
||||||
if (KFGIE != None)
|
foreach SpawnListRW(SE)
|
||||||
{
|
{
|
||||||
KFGIE.SpawnManagerClasses.AddItem(SpawnManagerE);
|
CycleWaveShift = Min(CycleWaveShift, SE.Wave);
|
||||||
|
CycleWaveSize = Max(CycleWaveSize, SE.Wave);
|
||||||
}
|
}
|
||||||
else
|
CycleWaveSize = CycleWaveSize - CycleWaveShift + 1;
|
||||||
{
|
|
||||||
KFGIS.SpawnManagerClasses.AddItem(SpawnManagerS);
|
|
||||||
KFGIS.SpawnManagerClasses.AddItem(SpawnManagerN);
|
|
||||||
KFGIS.SpawnManagerClasses.AddItem(SpawnManagerL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NeedInitSM)
|
|
||||||
{
|
|
||||||
KFGIS.InitSpawnManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
`ZS_Info("SpawnManager replaced");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PreparePreloadContent();
|
PreloadContent();
|
||||||
|
|
||||||
if (SpawnListSW.Length > 0 || SpawnListBW.Length > 0 || SpawnListR.Length > 0)
|
SetTimer(float(dt), true, nameof(SpawnTimer));
|
||||||
{
|
|
||||||
SetTimer(float(dt), true, nameof(SpawnTimer));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
`ZS_Info("Spawn timer disabled (no spawn lists)", LogLevel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function PreparePreloadContent()
|
private function PreloadContent()
|
||||||
{
|
{
|
||||||
local class<KFPawn_Monster> PawnClass;
|
local class<KFPawn_Monster> PawnClass;
|
||||||
|
|
||||||
ExtractCustomZedsFromSpawnList(SpawnListR, CustomZeds);
|
ExtractCustomZedsFromSpawnList(SpawnListRW, CustomZeds);
|
||||||
ExtractCustomZedsFromSpawnList(SpawnListBW, CustomZeds);
|
ExtractCustomZedsFromSpawnList(SpawnListBW, CustomZeds);
|
||||||
ExtractCustomZedsFromSpawnList(SpawnListSW, CustomZeds);
|
ExtractCustomZedsFromSpawnList(SpawnListSW, CustomZeds);
|
||||||
ExtractCustomZedsFromSpawnManager(AISpawnManager(KFGIS.SpawnManager), CustomZeds);
|
|
||||||
|
|
||||||
foreach CustomZeds(PawnClass)
|
foreach CustomZeds(PawnClass)
|
||||||
|
{
|
||||||
|
`ZS_Info("Preload content:" @ PawnClass);
|
||||||
PawnClass.static.PreloadContent();
|
PawnClass.static.PreloadContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ExtractCustomZedsFromSpawnList(Array<S_SpawnEntry> SpawnList, out Array<class<KFPawn_Monster> > Out)
|
private function ExtractCustomZedsFromSpawnList(Array<S_SpawnEntry> SpawnList, out Array<class<KFPawn_Monster> > Out)
|
||||||
@ -232,67 +220,17 @@ private function ExtractCustomZedsFromSpawnList(Array<S_SpawnEntry> SpawnList, o
|
|||||||
if (Out.Find(SE.ZedClass) == INDEX_NONE
|
if (Out.Find(SE.ZedClass) == INDEX_NONE
|
||||||
&& KFGIA.IsCustomZed(SE.ZedClass))
|
&& KFGIA.IsCustomZed(SE.ZedClass))
|
||||||
{
|
{
|
||||||
`ZS_Debug("Add custom zed:" @ SE.ZedClass);
|
|
||||||
Out.AddItem(SE.ZedClass);
|
Out.AddItem(SE.ZedClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ExtractCustomZedsFromSpawnManager(AISpawnManager SpawnManager, out Array<class<KFPawn_Monster> > Out)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
private function PreloadContent(Array<class<KFPawn_Monster> > Pawns)
|
|
||||||
{
|
|
||||||
local class<KFPawn_Monster> KFPM;
|
|
||||||
foreach Pawns(KFPM) KFPM.static.PreloadContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
if (CurrentBossClass == None)
|
|
||||||
{
|
|
||||||
foreach WorldInfo.AllPawns(class'KFPawn_Monster', KFPM)
|
|
||||||
{
|
|
||||||
Index = BossClassCache.Find(KFPM.class);
|
|
||||||
if (Index != INDEX_NONE)
|
|
||||||
{
|
|
||||||
CurrentBossClass = BossClassCache[Index];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentBossClass == None)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (SE.BossClass == CurrentBossClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function bool WaveConditionSpecial(S_SpawnEntry SE)
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
return (SE.Wave == SpecialWave);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function SpawnTimer()
|
private function SpawnTimer()
|
||||||
{
|
{
|
||||||
|
local S_SpawnEntry SE;
|
||||||
|
local int Index;
|
||||||
|
local float Threshold;
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
if (KFGIS.WaveNum != 0 && CurrentWave < KFGIS.WaveNum)
|
if (KFGIS.WaveNum != 0 && CurrentWave < KFGIS.WaveNum)
|
||||||
@ -306,47 +244,102 @@ private function SpawnTimer()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SpawnListCurrent.Length == 0)
|
||||||
|
{
|
||||||
|
SpawnTimerLogger(true, "No spawn list for this wave");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (CfgSpawn.default.AliveSpawnLimit > 0 && KFGIS.AIAliveCount >= CfgSpawn.default.AliveSpawnLimit)
|
if (CfgSpawn.default.AliveSpawnLimit > 0 && KFGIS.AIAliveCount >= CfgSpawn.default.AliveSpawnLimit)
|
||||||
{
|
{
|
||||||
SpawnTimerLogger(true, "alive spawn limit reached");
|
SpawnTimerLogger(true, "alive spawn limit reached");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!KFGIS.MyKFGRI.IsBossWave() && CfgSpawn.default.bShadowSpawn)
|
||||||
|
{
|
||||||
|
if (NoFreeSpawnSlots || KFGIS.MyKFGRI.AIRemaining <= KFGIS.AIAliveCount)
|
||||||
|
{
|
||||||
|
NoFreeSpawnSlots = true;
|
||||||
|
SpawnTimerLogger(true, "no free spawn slots");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnTimerLogger(false, SpawnListsComment);
|
||||||
|
|
||||||
|
Threshold = 1.0f - (float(KFGIS.MyKFGRI.AIRemaining) / float(WaveTotalAI));
|
||||||
|
foreach SpawnListCurrent(SE, Index)
|
||||||
|
{
|
||||||
|
if (NoFreeSpawnSlots)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!KFGIS.MyKFGRI.IsBossWave() && CfgSpawn.default.bShadowSpawn && KFGIS.MyKFGRI.AIRemaining <= KFGIS.AIAliveCount)
|
if (SE.RelativeStart != 0.0f && SE.RelativeStart > Threshold)
|
||||||
{
|
{
|
||||||
SpawnTimerLogger(true, "shadow spawn is active and no free spawn slots");
|
continue;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
if (SE.Delay > 0)
|
||||||
SpawnTimerLogger(false);
|
{
|
||||||
|
SpawnListCurrent[Index].Delay -= dt;
|
||||||
if ((SpecialWave == INDEX_NONE && !KFGIS.MyKFGRI.IsBossWave())
|
continue;
|
||||||
|| (SpecialWave != INDEX_NONE && !CfgSpawnListSW.default.bStopRegularSpawn)
|
}
|
||||||
|| (KFGIS.MyKFGRI.IsBossWave() && !CfgSpawnListBW.default.bStopRegularSpawn))
|
|
||||||
{
|
if (SE.SpawnsLeft > 0)
|
||||||
SpawnZeds(SpawnListR, WaveConditionRegular);
|
{
|
||||||
}
|
SpawnEntry(SpawnListCurrent, Index);
|
||||||
|
}
|
||||||
if (SpecialWave != INDEX_NONE)
|
|
||||||
{
|
|
||||||
SpawnZeds(SpawnListSW, WaveConditionSpecial);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KFGIS.MyKFGRI.IsBossWave())
|
|
||||||
{
|
|
||||||
SpawnZeds(SpawnListBW, WaveConditionBoss);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function SetupWave()
|
private function SetupWave()
|
||||||
{
|
{
|
||||||
local int WaveTotalAIDef;
|
local Array<String> SpawnListNames;
|
||||||
|
local int WaveTotalAIDef;
|
||||||
|
local String WaveTypeInfo;
|
||||||
|
local S_SpawnEntry SE;
|
||||||
|
local EAIType SWType;
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
|
if (CfgSpawn.default.bCyclicalSpawn && KFGIS.WaveNum > 1 && KFGIS.WaveNum == CycleWaveShift + CycleWaveSize * CurrentCycle)
|
||||||
|
{
|
||||||
|
CurrentCycle++;
|
||||||
|
`ZS_Info("Spawn cycle started:" @ CurrentCycle);
|
||||||
|
}
|
||||||
|
|
||||||
CurrentWave = KFGIS.WaveNum;
|
CurrentWave = KFGIS.WaveNum;
|
||||||
|
|
||||||
if (!KFGIS.MyKFGRI.IsBossWave())
|
if (KFGIE != None)
|
||||||
|
{
|
||||||
|
if (KFGameReplicationInfo_Endless(KFGIE.GameReplicationInfo).CurrentWeeklyMode != INDEX_NONE)
|
||||||
|
{
|
||||||
|
WaveTypeInfo = "Weekly:" @ KFGameReplicationInfo_Endless(KFGIE.GameReplicationInfo).CurrentWeeklyMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecialWave = KFGameReplicationInfo_Endless(KFGIE.GameReplicationInfo).CurrentSpecialMode;
|
||||||
|
if (SpecialWave != INDEX_NONE)
|
||||||
|
{
|
||||||
|
SWType = EAIType(SpecialWave);
|
||||||
|
WaveTypeInfo = "Special:" @ SWType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KFGIS.MyKFGRI.IsBossWave())
|
||||||
|
{
|
||||||
|
CurrentBossClass = KFGIA.BossAITypePawn(EBossAIType(KFGIS.MyKFGRI.BossIndex));
|
||||||
|
if (CurrentBossClass == None)
|
||||||
|
{
|
||||||
|
`ZS_Error("Can't determine boss class. Boss index:" @ KFGIS.MyKFGRI.BossIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WaveTypeInfo = "Boss:" @ CurrentBossClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
WaveTotalAIDef = KFGIS.SpawnManager.WaveTotalAI;
|
WaveTotalAIDef = KFGIS.SpawnManager.WaveTotalAI;
|
||||||
KFGIS.SpawnManager.WaveTotalAI *= CfgSpawn.default.ZedTotalMultiplier;
|
KFGIS.SpawnManager.WaveTotalAI *= CfgSpawn.default.ZedTotalMultiplier;
|
||||||
@ -358,33 +351,61 @@ private function SetupWave()
|
|||||||
{
|
{
|
||||||
`ZS_Info("increase WaveTotalAI from" @ WaveTotalAIDef @ "to" @ WaveTotalAI @ "due to ZedTotalMultiplier" @ "(" $ CfgSpawn.default.ZedTotalMultiplier $ ")");
|
`ZS_Info("increase WaveTotalAI from" @ WaveTotalAIDef @ "to" @ WaveTotalAI @ "due to ZedTotalMultiplier" @ "(" $ CfgSpawn.default.ZedTotalMultiplier $ ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CurrentBossClass = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CfgSpawn.default.bCyclicalSpawn && KFGIS.WaveNum > 1 && KFGIS.WaveNum == CycleWaveShift + CycleWaveSize * CurrentCycle)
|
NoFreeSpawnSlots = false;
|
||||||
|
UseBossSpawnList = KFGIS.MyKFGRI.IsBossWave();
|
||||||
|
UseSpecialSpawnList = (SpecialWave != INDEX_NONE);
|
||||||
|
UseRegularSpawnList = ((!UseSpecialSpawnList && !UseBossSpawnList)
|
||||||
|
|| (UseSpecialSpawnList && !CfgSpawnListSW.default.bStopRegularSpawn)
|
||||||
|
|| (UseBossSpawnList && !CfgSpawnListBW.default.bStopRegularSpawn));
|
||||||
|
|
||||||
|
SpawnListCurrent.Length = 0;
|
||||||
|
if (UseRegularSpawnList)
|
||||||
{
|
{
|
||||||
CurrentCycle++;
|
SpawnListNames.AddItem("regular");
|
||||||
`ZS_Info("Next spawn cycle started:" @ CurrentCycle);
|
foreach SpawnListRW(SE)
|
||||||
|
if (SE.Wave == KFGIS.WaveNum - CycleWaveSize * (CurrentCycle - 1))
|
||||||
|
SpawnListCurrent.AddItem(SE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetSpawnList(SpawnListR);
|
if (UseSpecialSpawnList)
|
||||||
ResetSpawnList(SpawnListSW);
|
|
||||||
ResetSpawnList(SpawnListBW);
|
|
||||||
|
|
||||||
CurrentBossClass = None;
|
|
||||||
|
|
||||||
if (KFGIE != None)
|
|
||||||
{
|
{
|
||||||
SpecialWave = KFGameReplicationInfo_Endless(KFGIE.GameReplicationInfo).CurrentSpecialMode;
|
SpawnListNames.AddItem("special");
|
||||||
|
foreach SpawnListSW(SE)
|
||||||
|
if (SE.Wave == SpecialWave)
|
||||||
|
SpawnListCurrent.AddItem(SE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UseBossSpawnList)
|
||||||
|
{
|
||||||
|
SpawnListNames.AddItem("boss");
|
||||||
|
foreach SpawnListBW(SE)
|
||||||
|
if (SE.BossClass == CurrentBossClass)
|
||||||
|
SpawnListCurrent.AddItem(SE);
|
||||||
|
}
|
||||||
|
|
||||||
|
JoinArray(SpawnListNames, SpawnListsComment, ", ");
|
||||||
|
AdjustSpawnList(SpawnListCurrent);
|
||||||
|
|
||||||
|
if (WaveTypeInfo != "")
|
||||||
|
{
|
||||||
|
WaveTypeInfo = "(" $ WaveTypeInfo $ ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
`ZS_Info("Wave" @ CurrentWave @ WaveTypeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ResetSpawnList(out Array<S_SpawnEntry> List)
|
private function AdjustSpawnList(out Array<S_SpawnEntry> List)
|
||||||
{
|
{
|
||||||
local S_SpawnEntry SE;
|
local S_SpawnEntry SE;
|
||||||
local int Index;
|
local int Index;
|
||||||
local float Cycle, Players;
|
local float Cycle, Players;
|
||||||
local float MSB, MSC, MSP;
|
local float MSB, MSC, MSP;
|
||||||
local float MLB, MLC, MLP;
|
local float MLB, MLC, MLP;
|
||||||
|
local int ZedNameMaxLength;
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
@ -399,8 +420,10 @@ private function ResetSpawnList(out Array<S_SpawnEntry> List)
|
|||||||
MLC = CfgSpawn.default.SingleSpawnLimitCycleMultiplier;
|
MLC = CfgSpawn.default.SingleSpawnLimitCycleMultiplier;
|
||||||
MLP = CfgSpawn.default.SingleSpawnLimitPlayerMultiplier;
|
MLP = CfgSpawn.default.SingleSpawnLimitPlayerMultiplier;
|
||||||
|
|
||||||
|
ZedNameMaxLength = 0;
|
||||||
foreach List(SE, Index)
|
foreach List(SE, Index)
|
||||||
{
|
{
|
||||||
|
ZedNameMaxLength = Max(ZedNameMaxLength, Len(String(SE.ZedClass)));
|
||||||
if (KFGIS.MyKFGRI.IsBossWave())
|
if (KFGIS.MyKFGRI.IsBossWave())
|
||||||
{
|
{
|
||||||
List[Index].RelativeStart = 0.f;
|
List[Index].RelativeStart = 0.f;
|
||||||
@ -409,22 +432,27 @@ private function ResetSpawnList(out Array<S_SpawnEntry> List)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
List[Index].RelativeStart = SE.RelativeStartDefault;
|
List[Index].RelativeStart = SE.RelativeStartDefault;
|
||||||
if (SE.RelativeStart == 0.f)
|
if (List[Index].RelativeStart == 0.f)
|
||||||
List[Index].Delay = SE.DelayDefault;
|
List[Index].Delay = SE.DelayDefault;
|
||||||
else
|
else
|
||||||
List[Index].Delay = 0;
|
List[Index].Delay = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
List[Index].SpawnsTotal = Round(SE.SpawnCountBase * (MSB + MSC * (Cycle - 1.0f) + MSP * (Players - 1.0f)));
|
List[Index].ForceSpawn = false;
|
||||||
List[Index].SpawnsLeft = List[Index].SpawnsTotal;
|
List[Index].SpawnsTotal = Round(SE.SpawnCountBase * (MSB + MSC * (Cycle - 1.0f) + MSP * (Players - 1.0f)));
|
||||||
|
|
||||||
List[Index].SingleSpawnLimit = Round(SE.SingleSpawnLimitDefault * (MLB + MLC * (Cycle - 1.0f) + MLP * (Players - 1.0f)));
|
List[Index].SingleSpawnLimit = Round(SE.SingleSpawnLimitDefault * (MLB + MLC * (Cycle - 1.0f) + MLP * (Players - 1.0f)));
|
||||||
|
List[Index].SpawnsLeft = List[Index].SpawnsTotal;
|
||||||
`ZS_Debug(SE.ZedClass @ "SpawnsTotal:" @ List[Index].SpawnsTotal @ "SingleSpawnLimit:" @ List[Index].SingleSpawnLimit);
|
}
|
||||||
|
|
||||||
|
foreach List(SE, Index)
|
||||||
|
{
|
||||||
|
List[Index].ZedNameFiller = "";
|
||||||
|
while (Len(String(SE.ZedClass)) + Len(List[Index].ZedNameFiller) < ZedNameMaxLength)
|
||||||
|
List[Index].ZedNameFiller @= "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function SpawnTimerLogger(bool Stop, optional String Reason)
|
private function SpawnTimerLogger(bool Stop, optional String Comment)
|
||||||
{
|
{
|
||||||
local String Message;
|
local String Message;
|
||||||
|
|
||||||
@ -435,101 +463,95 @@ private function SpawnTimerLogger(bool Stop, optional String Reason)
|
|||||||
else
|
else
|
||||||
Message = "Start spawn";
|
Message = "Start spawn";
|
||||||
|
|
||||||
if (Reason != "")
|
if (Comment != "")
|
||||||
Message @= "(" $ Reason $ ")";
|
Message @= "(" $ Comment $ ")";
|
||||||
|
|
||||||
if (Message != SpawnTimerLastMessage)
|
if (SpawnActive == Stop)
|
||||||
{
|
{
|
||||||
`ZS_Info(Message);
|
`ZS_Info(Message);
|
||||||
SpawnTimerLastMessage = Message;
|
SpawnActive = !Stop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function SpawnZeds(out Array<S_SpawnEntry> SpawnList, delegate<WaveCondition> Condition)
|
|
||||||
{
|
|
||||||
local S_SpawnEntry SE;
|
|
||||||
local int Index;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
foreach SpawnList(SE, Index)
|
|
||||||
{
|
|
||||||
if (Condition(SE))
|
|
||||||
{
|
|
||||||
if (!ReadyToStart(SE)) continue;
|
|
||||||
|
|
||||||
if (ReadyToSpawn(SE))
|
|
||||||
SpawnEntry(SpawnListR, Index);
|
|
||||||
else
|
|
||||||
SpawnListR[Index].Delay -= dt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function bool ReadyToStart(S_SpawnEntry SE)
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
if (SE.RelativeStart == 0.f)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (SE.RelativeStart <= 1.0f - (float(KFGIS.MyKFGRI.AIRemaining) / float(WaveTotalAI)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function bool ReadyToSpawn(S_SpawnEntry SE)
|
|
||||||
{
|
|
||||||
`ZS_Trace(`Location);
|
|
||||||
|
|
||||||
return SE.Delay <= 0 && SE.SpawnsLeft > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function SpawnEntry(out Array<S_SpawnEntry> SpawnList, int Index)
|
private function SpawnEntry(out Array<S_SpawnEntry> SpawnList, int Index)
|
||||||
{
|
{
|
||||||
local S_SpawnEntry SE;
|
local S_SpawnEntry SE;
|
||||||
local int FreeSpawnSlots, SpawnCount, Spawned;
|
local int FreeSpawnSlots, SpawnCount, Spawned;
|
||||||
local String Message;
|
local String Action, Comment, NextSpawn;
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
SE = SpawnList[Index];
|
SE = SpawnList[Index];
|
||||||
|
|
||||||
SpawnList[Index].Delay = SE.DelayDefault;
|
SpawnList[Index].Delay = SE.DelayDefault;
|
||||||
if (FRand() <= SE.Probability)
|
if (FRand() <= SE.Probability || SE.ForceSpawn)
|
||||||
{
|
{
|
||||||
if (SE.SingleSpawnLimit == 0 || SE.SpawnsLeft < SE.SingleSpawnLimit)
|
if (SE.SingleSpawnLimit == 0 || SE.SpawnsLeft < SE.SingleSpawnLimit)
|
||||||
|
{
|
||||||
SpawnCount = SE.SpawnsLeft;
|
SpawnCount = SE.SpawnsLeft;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
SpawnCount = SE.SingleSpawnLimit;
|
SpawnCount = SE.SingleSpawnLimit;
|
||||||
|
}
|
||||||
|
|
||||||
if (CfgSpawn.default.bShadowSpawn && !KFGIS.MyKFGRI.IsBossWave())
|
if (CfgSpawn.default.bShadowSpawn && !KFGIS.MyKFGRI.IsBossWave())
|
||||||
{
|
{
|
||||||
FreeSpawnSlots = KFGIS.MyKFGRI.AIRemaining - KFGIS.AIAliveCount;
|
FreeSpawnSlots = KFGIS.MyKFGRI.AIRemaining - KFGIS.AIAliveCount;
|
||||||
if (SpawnCount > FreeSpawnSlots)
|
if (FreeSpawnSlots == 0)
|
||||||
|
{
|
||||||
|
NoFreeSpawnSlots = true;
|
||||||
|
SpawnList[Index].SpawnsLeft = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (SpawnCount > FreeSpawnSlots)
|
||||||
{
|
{
|
||||||
`ZS_Info("Not enough free slots to spawn, will spawn" @ FreeSpawnSlots @ "instead of" @ SpawnCount);
|
|
||||||
SpawnCount = FreeSpawnSlots;
|
SpawnCount = FreeSpawnSlots;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spawned = SpawnZed(SE.ZedClass, SpawnCount, SE.SpawnAtPlayerStart);
|
Spawned = SpawnZed(SE.ZedClass, SpawnCount, SE.SpawnAtPlayerStart);
|
||||||
Message = "Spawned:" @ SE.ZedClass @ "x" $ Spawned;
|
if (Spawned == INDEX_NONE)
|
||||||
|
{
|
||||||
|
SpawnList[Index].Delay = 5;
|
||||||
|
SpawnList[Index].ForceSpawn = true;
|
||||||
|
Action = "Skip spawn";
|
||||||
|
Comment = "no free spawn volume, try to spawn it again in" @ SpawnList[Index].Delay @ "seconds...";
|
||||||
|
SpawnLog(SE, Action, Comment);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (Spawned == 0)
|
||||||
|
{
|
||||||
|
Action = "Spawn failed";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpawnList[Index].ForceSpawn = false;
|
||||||
|
Action = "Spawned";
|
||||||
|
Comment = "x" $ Spawned;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Message = "Skip spawn" @ SE.ZedClass @ "due to probability:" @ SE.Probability * 100 $ "%";
|
Action = "Skip spawn";
|
||||||
|
Comment = "due to" @ Round(SE.Probability * 100) $ "%" @ "probability";
|
||||||
Spawned = SE.SingleSpawnLimit;
|
Spawned = SE.SingleSpawnLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnList[Index].SpawnsLeft -= Spawned;
|
SpawnList[Index].SpawnsLeft -= Spawned;
|
||||||
if (SpawnList[Index].SpawnsLeft > 0)
|
if (SpawnList[Index].SpawnsLeft > 0)
|
||||||
{
|
{
|
||||||
Message @= "(Next spawn after" @ SE.DelayDefault $ "sec," @ "spawns left:" @ SpawnList[Index].SpawnsLeft $ ")";
|
NextSpawn = "next after" @ SE.DelayDefault $ "sec," @ "pawns left:" @ SpawnList[Index].SpawnsLeft;
|
||||||
}
|
}
|
||||||
`ZS_Info(Message);
|
SpawnLog(SE, Action, Comment, NextSpawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function SpawnLog(S_SpawnEntry SE, String Action, optional String Comment, optional String NextSpawn)
|
||||||
|
{
|
||||||
|
if (Comment != "") Comment = ":" @ Comment;
|
||||||
|
if (NextSpawn != "") NextSpawn = "(" $ NextSpawn $ ")";
|
||||||
|
|
||||||
|
`ZS_Info(String(SE.ZedClass) $ SE.ZedNameFiller @ ">" @ Action $ Comment @ NextSpawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function int PlayerCount()
|
private function int PlayerCount()
|
||||||
@ -574,59 +596,76 @@ private function Vector PlayerStartLocation()
|
|||||||
private function int SpawnZed(class<KFPawn_Monster> ZedClass, int SpawnCount, bool SpawnAtPlayerStart)
|
private function int SpawnZed(class<KFPawn_Monster> ZedClass, int SpawnCount, bool SpawnAtPlayerStart)
|
||||||
{
|
{
|
||||||
local Array<class<KFPawn_Monster> > CustomSquad;
|
local Array<class<KFPawn_Monster> > CustomSquad;
|
||||||
local Vector SpawnLocation;
|
local Vector SpawnLocation, PlayerStart;
|
||||||
|
local KFSpawnVolume SpawnVolume;
|
||||||
local KFPawn_Monster KFPM;
|
local KFPawn_Monster KFPM;
|
||||||
local Controller C;
|
local Controller C;
|
||||||
local int SpawnFailed;
|
local int Failed, Spawned;
|
||||||
local int Index;
|
local int Index;
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
for (Index = 0; Index < SpawnCount; Index++)
|
PlayerStart = PlayerStartLocation();
|
||||||
CustomSquad.AddItem(ZedClass);
|
|
||||||
|
|
||||||
if (SpawnAtPlayerStart)
|
if (SpawnAtPlayerStart)
|
||||||
{
|
{
|
||||||
SpawnLocation = PlayerStartLocation();
|
SpawnLocation = PlayerStart;
|
||||||
SpawnLocation.Y += 64;
|
SpawnLocation.Y += 64;
|
||||||
SpawnLocation.Z += 64;
|
SpawnLocation.Z += 64;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SpawnLocation = KFGIS.SpawnManager.GetBestSpawnVolume(CustomSquad).Location;
|
for (Index = 0; Index < SpawnCount; Index++)
|
||||||
|
{
|
||||||
|
CustomSquad.AddItem(ZedClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnVolume = KFGIS.SpawnManager.GetBestSpawnVolume(CustomSquad);
|
||||||
|
if (SpawnVolume == None)
|
||||||
|
{
|
||||||
|
return INDEX_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnLocation = SpawnVolume.Location;
|
||||||
|
if (SpawnLocation == PlayerStart)
|
||||||
|
{
|
||||||
|
return INDEX_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
SpawnLocation.Z += 10;
|
SpawnLocation.Z += 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnFailed = 0;
|
Spawned = 0; Failed = 0;
|
||||||
for (Index = 0; Index < SpawnCount; Index++)
|
while (Failed + Spawned < SpawnCount)
|
||||||
{
|
{
|
||||||
KFPM = Spawn(ZedClass,,, SpawnLocation, rot(0,0,1),, true);
|
KFPM = Spawn(ZedClass,,, SpawnLocation, rot(0,0,1),, true);
|
||||||
if (KFPM == None)
|
if (KFPM == None)
|
||||||
{
|
{
|
||||||
`ZS_Error("Can't spawn" @ ZedClass);
|
`ZS_Error("Can't spawn" @ ZedClass);
|
||||||
SpawnFailed++;
|
Failed++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
C = KFPM.Spawn(KFPM.ControllerClass);
|
C = KFPM.Spawn(KFPM.ControllerClass);
|
||||||
if (C == None)
|
if (C == None)
|
||||||
{
|
{
|
||||||
`ZS_Error("Can't spawn controller for" @ ZedClass $ ". Destroy this KFPawn...");
|
`ZS_Error("Can't spawn controller for" @ ZedClass $ ". Destroy this" @ KFPM $ "...");
|
||||||
KFPM.Destroy();
|
KFPM.Destroy();
|
||||||
SpawnFailed++;
|
Failed++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
C.Possess(KFPM, false);
|
C.Possess(KFPM, false);
|
||||||
}
|
Spawned++;
|
||||||
|
|
||||||
if (CfgSpawn.default.bShadowSpawn && !KFGIS.MyKFGRI.IsBossWave())
|
|
||||||
{
|
|
||||||
KFGIS.MyKFGRI.AIRemaining -= (SpawnCount - SpawnFailed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KFGIS.RefreshMonsterAliveCount();
|
if (CfgSpawn.default.bShadowSpawn && !KFGIS.MyKFGRI.IsBossWave())
|
||||||
|
{
|
||||||
return SpawnCount - SpawnFailed;
|
KFGIS.NumAIFinishedSpawning += Spawned;
|
||||||
|
KFGIS.NumAISpawnsQueued += Spawned;
|
||||||
|
}
|
||||||
|
|
||||||
|
KFGIS.UpdateAIRemaining();
|
||||||
|
|
||||||
|
return Spawned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function NotifyLogin(Controller C)
|
public function NotifyLogin(Controller C)
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
class _CommonTypes extends Object;
|
|
||||||
|
|
||||||
enum E_LogLevel
|
|
||||||
{
|
|
||||||
LL_WrongLevel,
|
|
||||||
LL_Fatal,
|
|
||||||
LL_Error,
|
|
||||||
LL_Warning,
|
|
||||||
LL_Info,
|
|
||||||
LL_Debug,
|
|
||||||
LL_Trace,
|
|
||||||
LL_All
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultproperties
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -8,3 +8,5 @@
|
|||||||
`define ZS_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `ZS_Tag)
|
`define ZS_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `ZS_Tag)
|
||||||
`define ZS_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `ZS_Tag)
|
`define ZS_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `ZS_Tag)
|
||||||
`define ZS_Trace(msg) `log("TRACE:" @ `msg, (LogLevel >= LL_Trace), `ZS_Tag)
|
`define ZS_Trace(msg) `log("TRACE:" @ `msg, (LogLevel >= LL_Trace), `ZS_Tag)
|
||||||
|
|
||||||
|
`define NO_CONFIG 0
|
Reference in New Issue
Block a user