...
- now the type of unit affects the choice of spawn location - bSpawnAtPlayerStart removed from spawn list - SpawnAtPlayerStart can be set separately for specified maps or zed classes - optimized spawn list loading - added handling of the situation when the player leaves the game before preloadcontent synchronization ends - fixed calculation of the number of zeds in some cases
This commit is contained in:
parent
e1face5c04
commit
90a69ef739
@ -56,7 +56,6 @@ Use the [b][ZedSpawner.SpawnListBossWaves][/b] and [b][ZedSpawner.SpawnListSpeci
|
|||||||
[*][b]Probability[/b] - the chance (%) of each spawn (1-100).
|
[*][b]Probability[/b] - the chance (%) of each spawn (1-100).
|
||||||
[*][b]SpawnCountBase[/b] - The base number of zeds to spawn, aka the number of zeds that will be spawned on the first cycle with one player. Can be adjusted by modifiers, number of players and cycle number.
|
[*][b]SpawnCountBase[/b] - The base number of zeds to spawn, aka the number of zeds that will be spawned on the first cycle with one player. Can be adjusted by modifiers, number of players and cycle number.
|
||||||
[*][b]SingleSpawnLimit[/b] - maximum number of zeds for one spawn. Can be adjusted by modifiers, number of players and cycle number.
|
[*][b]SingleSpawnLimit[/b] - maximum number of zeds for one spawn. Can be adjusted by modifiers, number of players and cycle number.
|
||||||
[*][b]bSpawnAtPlayerStart[/b] - exactly what is written.
|
|
||||||
[/list]
|
[/list]
|
||||||
|
|
||||||
[h1]Spawn logic[/h1]
|
[h1]Spawn logic[/h1]
|
||||||
@ -65,7 +64,5 @@ I really tried to describe in text how it works, but every time I got some kind
|
|||||||
[h1]📌[url=https://redirect.genzmey.su/kf2-zedspawner-calc]Spawn calculator[/url][/h1]
|
[h1]📌[url=https://redirect.genzmey.su/kf2-zedspawner-calc]Spawn calculator[/url][/h1]
|
||||||
[i]Just please try not to interfere with each other if you see that someone is already using a calculator.[/i]
|
[i]Just please try not to interfere with each other if you see that someone is already using a calculator.[/i]
|
||||||
|
|
||||||
By the way, ZedSpawner logs everything it does, so reading the logs can also help you figure out how it works.
|
|
||||||
|
|
||||||
[h1]Sources[/h1]
|
[h1]Sources[/h1]
|
||||||
[url=https://github.com/GenZmeY/KF2-ZedSpawner]https://github.com/GenZmeY/KF2-ZedSpawner[/url] (GNU GPLv3)
|
[url=https://github.com/GenZmeY/KF2-ZedSpawner]https://github.com/GenZmeY/KF2-ZedSpawner[/url] (GNU GPLv3)
|
||||||
|
BIN
PublicationContent/previewFull.gif
Normal file
BIN
PublicationContent/previewFull.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
77
ZedSpawner/Classes/SpawnAtPlayerStart.uc
Normal file
77
ZedSpawner/Classes/SpawnAtPlayerStart.uc
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
class SpawnAtPlayerStart extends Object
|
||||||
|
dependson(ZedSpawner)
|
||||||
|
config(ZedSpawner);
|
||||||
|
|
||||||
|
var private config Array<String> ZedClass;
|
||||||
|
var public config Array<String> Map;
|
||||||
|
|
||||||
|
public static function InitConfig(int Version, int LatestVersion)
|
||||||
|
{
|
||||||
|
switch (Version)
|
||||||
|
{
|
||||||
|
case `NO_CONFIG:
|
||||||
|
case 2:
|
||||||
|
ApplyDefault();
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LatestVersion != Version)
|
||||||
|
{
|
||||||
|
StaticSaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function ApplyDefault()
|
||||||
|
{
|
||||||
|
default.ZedClass.Length = 0;
|
||||||
|
default.ZedClass.AddItem("HL2Monsters.Combine_Strider");
|
||||||
|
default.ZedClass.AddItem("HL2Monsters.Combine_Gunship");
|
||||||
|
default.ZedClass.AddItem("HL2Monsters.Hunter_Chopper");
|
||||||
|
default.ZedClass.AddItem("SomePackage.SomeZedClassYouWantToSpawnAtPlayerStart");
|
||||||
|
|
||||||
|
default.Map.Length = 0;
|
||||||
|
default.Map.AddItem("KF-SomeMapNameWhereYouWantSpawnZedsAtPlayerStart");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function Array<class<KFPawn_Monster> > Load(E_LogLevel LogLevel)
|
||||||
|
{
|
||||||
|
local Array<class<KFPawn_Monster> > ZedList;
|
||||||
|
local class<KFPawn_Monster> KFPMC;
|
||||||
|
local String ZedClassTmp;
|
||||||
|
local int Line, Loaded;
|
||||||
|
|
||||||
|
Loaded = 0;
|
||||||
|
|
||||||
|
`ZS_Info("Load zeds to spawn at player start:");
|
||||||
|
foreach default.ZedClass(ZedClassTmp, Line)
|
||||||
|
{
|
||||||
|
KFPMC = class<KFPawn_Monster>(DynamicLoadObject(ZedClassTmp, class'Class'));
|
||||||
|
if (KFPMC == None)
|
||||||
|
{
|
||||||
|
`ZS_Warn("[" $ Line + 1 $ "]" @ "Can't load zed class:" @ ZedClassTmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Loaded++;
|
||||||
|
ZedList.AddItem(KFPMC);
|
||||||
|
`ZS_Debug("[" $ Line + 1 $ "]" @ "Loaded successfully:" @ ZedClassTmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Loaded == default.ZedClass.Length)
|
||||||
|
{
|
||||||
|
`ZS_Info("Spawn at player start list (Zeds) loaded successfully (" $ default.ZedClass.Length @ "entries)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
`ZS_Info("Spawn at player start list (Zeds): loaded" @ Loaded @ "of" @ default.ZedClass.Length @ "entries");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZedList;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -10,7 +10,6 @@ struct S_SpawnEntryCfg
|
|||||||
var int Probability;
|
var int Probability;
|
||||||
var int SpawnCountBase;
|
var int SpawnCountBase;
|
||||||
var int SingleSpawnLimit;
|
var int SingleSpawnLimit;
|
||||||
var bool bSpawnAtPlayerStart;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var public config bool bStopRegularSpawn;
|
var public config bool bStopRegularSpawn;
|
||||||
@ -47,7 +46,6 @@ private static function ApplyDefault(KFGI_Access KFGIA)
|
|||||||
SpawnEntry.SingleSpawnLimit = 1;
|
SpawnEntry.SingleSpawnLimit = 1;
|
||||||
SpawnEntry.Delay = 30;
|
SpawnEntry.Delay = 30;
|
||||||
SpawnEntry.Probability = 100;
|
SpawnEntry.Probability = 100;
|
||||||
SpawnEntry.bSpawnAtPlayerStart = false;
|
|
||||||
KFPM_Bosses = KFGIA.GetAIBossClassList();
|
KFPM_Bosses = KFGIA.GetAIBossClassList();
|
||||||
foreach KFPM_Bosses(KFPMC)
|
foreach KFPM_Bosses(KFPMC)
|
||||||
{
|
{
|
||||||
@ -65,7 +63,7 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
local bool Errors;
|
local bool Errors;
|
||||||
local int Loaded;
|
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;
|
||||||
@ -114,8 +112,6 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
Errors = true;
|
Errors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnEntry.SpawnAtPlayerStart = SpawnEntryCfg.bSpawnAtPlayerStart;
|
|
||||||
|
|
||||||
if (!Errors)
|
if (!Errors)
|
||||||
{
|
{
|
||||||
Loaded++;
|
Loaded++;
|
||||||
@ -126,7 +122,7 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
|
|
||||||
if (Loaded == default.Spawn.Length)
|
if (Loaded == default.Spawn.Length)
|
||||||
{
|
{
|
||||||
`ZS_Info("Boss spawn list loaded successfully");
|
`ZS_Info("Boss spawn list loaded successfully (" $ default.Spawn.Length @ "entries)");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -11,11 +11,15 @@ struct S_SpawnEntryCfg
|
|||||||
var int Probability;
|
var int Probability;
|
||||||
var int SpawnCountBase;
|
var int SpawnCountBase;
|
||||||
var int SingleSpawnLimit;
|
var int SingleSpawnLimit;
|
||||||
var bool bSpawnAtPlayerStart;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var public config Array<S_SpawnEntryCfg> Spawn;
|
var public config Array<S_SpawnEntryCfg> Spawn;
|
||||||
|
|
||||||
|
delegate int SpawnListSort(S_SpawnEntryCfg A, S_SpawnEntryCfg B)
|
||||||
|
{
|
||||||
|
return A.Wave > B.Wave ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
public static function InitConfig(int Version, int LatestVersion, KFGI_Access KFGIA)
|
public static function InitConfig(int Version, int LatestVersion, KFGI_Access KFGIA)
|
||||||
{
|
{
|
||||||
switch (Version)
|
switch (Version)
|
||||||
@ -46,7 +50,6 @@ private static function ApplyDefault(KFGI_Access KFGIA)
|
|||||||
SpawnEntry.RelativeStart = 25;
|
SpawnEntry.RelativeStart = 25;
|
||||||
SpawnEntry.Delay = 60;
|
SpawnEntry.Delay = 60;
|
||||||
SpawnEntry.Probability = 100;
|
SpawnEntry.Probability = 100;
|
||||||
SpawnEntry.bSpawnAtPlayerStart = false;
|
|
||||||
|
|
||||||
KFPM_Zeds = KFGIA.GetAIClassList();
|
KFPM_Zeds = KFGIA.GetAIClassList();
|
||||||
foreach KFPM_Zeds(KFPMC)
|
foreach KFPM_Zeds(KFPMC)
|
||||||
@ -120,8 +123,6 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
Errors = true;
|
Errors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnEntry.SpawnAtPlayerStart = SpawnEntryCfg.bSpawnAtPlayerStart;
|
|
||||||
|
|
||||||
if (!Errors)
|
if (!Errors)
|
||||||
{
|
{
|
||||||
Loaded++;
|
Loaded++;
|
||||||
@ -130,9 +131,11 @@ public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default.Spawn.Sort(SpawnListSort);
|
||||||
|
|
||||||
if (Loaded == default.Spawn.Length)
|
if (Loaded == default.Spawn.Length)
|
||||||
{
|
{
|
||||||
`ZS_Info("Regular spawn list loaded successfully");
|
`ZS_Info("Regular spawn list loaded successfully (" $ default.Spawn.Length @ "entries)");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,6 @@ struct S_SpawnEntryCfg
|
|||||||
var int Probability;
|
var int Probability;
|
||||||
var int SpawnCountBase;
|
var int SpawnCountBase;
|
||||||
var int SingleSpawnLimit;
|
var int SingleSpawnLimit;
|
||||||
var bool bSpawnAtPlayerStart;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var public config bool bStopRegularSpawn;
|
var public config bool bStopRegularSpawn;
|
||||||
@ -46,7 +45,6 @@ private static function ApplyDefault()
|
|||||||
SpawnEntry.RelativeStart = 0;
|
SpawnEntry.RelativeStart = 0;
|
||||||
SpawnEntry.Delay = 60;
|
SpawnEntry.Delay = 60;
|
||||||
SpawnEntry.Probability = 100;
|
SpawnEntry.Probability = 100;
|
||||||
SpawnEntry.bSpawnAtPlayerStart = false;
|
|
||||||
foreach class'KFGameInfo_Endless'.default.SpecialWaveTypes(AIType)
|
foreach class'KFGameInfo_Endless'.default.SpecialWaveTypes(AIType)
|
||||||
{
|
{
|
||||||
SpawnEntry.Wave = AIType;
|
SpawnEntry.Wave = AIType;
|
||||||
@ -123,8 +121,6 @@ public static function Array<S_SpawnEntry> Load(KFGameInfo_Endless KFGIE, E_LogL
|
|||||||
Errors = true;
|
Errors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnEntry.SpawnAtPlayerStart = SpawnEntryCfg.bSpawnAtPlayerStart;
|
|
||||||
|
|
||||||
if (!Errors)
|
if (!Errors)
|
||||||
{
|
{
|
||||||
Loaded++;
|
Loaded++;
|
||||||
@ -135,7 +131,7 @@ public static function Array<S_SpawnEntry> Load(KFGameInfo_Endless KFGIE, E_LogL
|
|||||||
|
|
||||||
if (Loaded == default.Spawn.Length)
|
if (Loaded == default.Spawn.Length)
|
||||||
{
|
{
|
||||||
`ZS_Info("Special spawn list loaded successfully");
|
`ZS_Info("Special spawn list loaded successfully (" $ default.Spawn.Length @ "entries)");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
class ZedSpawner extends Info
|
class ZedSpawner extends Info
|
||||||
config(ZedSpawner);
|
config(ZedSpawner);
|
||||||
|
|
||||||
const LatestVersion = 2;
|
const LatestVersion = 3;
|
||||||
|
|
||||||
const CfgSpawn = class'Spawn';
|
const CfgSpawn = class'Spawn';
|
||||||
const CfgSpawnListRW = class'SpawnListRegular';
|
const CfgSpawnAtPlayerStart = class'SpawnAtPlayerStart';
|
||||||
const CfgSpawnListBW = class'SpawnListBossWaves';
|
const CfgSpawnListRW = class'SpawnListRegular';
|
||||||
const CfgSpawnListSW = class'SpawnListSpecialWaves';
|
const CfgSpawnListBW = class'SpawnListBossWaves';
|
||||||
|
const CfgSpawnListSW = class'SpawnListSpecialWaves';
|
||||||
|
|
||||||
enum E_LogLevel
|
enum E_LogLevel
|
||||||
{
|
{
|
||||||
@ -35,7 +36,6 @@ struct S_SpawnEntry
|
|||||||
var float Delay;
|
var float Delay;
|
||||||
var int PawnsLeft;
|
var int PawnsLeft;
|
||||||
var int PawnsTotal;
|
var int PawnsTotal;
|
||||||
var bool SpawnAtPlayerStart;
|
|
||||||
var bool ForceSpawn;
|
var bool ForceSpawn;
|
||||||
var String ZedNameFiller;
|
var String ZedNameFiller;
|
||||||
};
|
};
|
||||||
@ -55,6 +55,7 @@ var private bool NoFreeSpawnSlots;
|
|||||||
var private bool UseRegularSpawnList;
|
var private bool UseRegularSpawnList;
|
||||||
var private bool UseBossSpawnList;
|
var private bool UseBossSpawnList;
|
||||||
var private bool UseSpecialSpawnList;
|
var private bool UseSpecialSpawnList;
|
||||||
|
var private bool GlobalSpawnAtPlayerStart;
|
||||||
|
|
||||||
var private KFGameInfo_Survival KFGIS;
|
var private KFGameInfo_Survival KFGIS;
|
||||||
var private KFGameInfo_Endless KFGIE;
|
var private KFGameInfo_Endless KFGIE;
|
||||||
@ -69,10 +70,18 @@ var private int WaveTotalAI;
|
|||||||
|
|
||||||
var private class<KFPawn_Monster> CurrentBossClass;
|
var private class<KFPawn_Monster> CurrentBossClass;
|
||||||
var private Array<class<KFPawn_Monster> > CustomZeds;
|
var private Array<class<KFPawn_Monster> > CustomZeds;
|
||||||
|
var private Array<class<KFPawn_Monster> > SpawnAtPlayerStartZeds;
|
||||||
|
|
||||||
var private bool SpawnActive;
|
var private bool SpawnActive;
|
||||||
var private String SpawnListsComment;
|
var private String SpawnListsComment;
|
||||||
|
|
||||||
|
var private Array<ZedSpawnerRepLink> RepLinks;
|
||||||
|
|
||||||
|
public simulated function bool SafeDestroy()
|
||||||
|
{
|
||||||
|
return (bPendingDelete || bDeleteMe || Destroy());
|
||||||
|
}
|
||||||
|
|
||||||
public event PreBeginPlay()
|
public event PreBeginPlay()
|
||||||
{
|
{
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
@ -80,7 +89,7 @@ public event PreBeginPlay()
|
|||||||
if (WorldInfo.NetMode == NM_Client)
|
if (WorldInfo.NetMode == NM_Client)
|
||||||
{
|
{
|
||||||
`ZS_Fatal("NetMode == NM_Client, Destroy...");
|
`ZS_Fatal("NetMode == NM_Client, Destroy...");
|
||||||
Destroy();
|
SafeDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +100,7 @@ public event PostBeginPlay()
|
|||||||
{
|
{
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
if (bPendingDelete) return;
|
if (bPendingDelete || bDeleteMe) return;
|
||||||
|
|
||||||
Super.PostBeginPlay();
|
Super.PostBeginPlay();
|
||||||
|
|
||||||
@ -102,12 +111,12 @@ private function InitConfig()
|
|||||||
{
|
{
|
||||||
if (Version == `NO_CONFIG)
|
if (Version == `NO_CONFIG)
|
||||||
{
|
{
|
||||||
Tickrate = 1.0f;
|
|
||||||
LogLevel = LL_Info;
|
LogLevel = LL_Info;
|
||||||
SaveConfig();
|
SaveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
CfgSpawn.static.InitConfig(Version, LatestVersion);
|
CfgSpawn.static.InitConfig(Version, LatestVersion);
|
||||||
|
CfgSpawnAtPlayerStart.static.InitConfig(Version, LatestVersion);
|
||||||
CfgSpawnListRW.static.InitConfig(Version, LatestVersion, KFGIA);
|
CfgSpawnListRW.static.InitConfig(Version, LatestVersion, KFGIA);
|
||||||
CfgSpawnListBW.static.InitConfig(Version, LatestVersion, KFGIA);
|
CfgSpawnListBW.static.InitConfig(Version, LatestVersion, KFGIA);
|
||||||
CfgSpawnListSW.static.InitConfig(Version, LatestVersion);
|
CfgSpawnListSW.static.InitConfig(Version, LatestVersion);
|
||||||
@ -120,6 +129,8 @@ private function InitConfig()
|
|||||||
case 1:
|
case 1:
|
||||||
Tickrate = 1.0f;
|
Tickrate = 1.0f;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
|
||||||
case MaxInt:
|
case MaxInt:
|
||||||
`ZS_Info("Config updated to version"@LatestVersion);
|
`ZS_Info("Config updated to version"@LatestVersion);
|
||||||
break;
|
break;
|
||||||
@ -145,6 +156,7 @@ private function InitConfig()
|
|||||||
private function Init()
|
private function Init()
|
||||||
{
|
{
|
||||||
local S_SpawnEntry SE;
|
local S_SpawnEntry SE;
|
||||||
|
local String CurrentMap;
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
@ -152,7 +164,7 @@ private function Init()
|
|||||||
if (KFGIS == None)
|
if (KFGIS == None)
|
||||||
{
|
{
|
||||||
`ZS_Fatal("Incompatible gamemode:" @ WorldInfo.Game $ ". Destroy...");
|
`ZS_Fatal("Incompatible gamemode:" @ WorldInfo.Game $ ". Destroy...");
|
||||||
Destroy();
|
SafeDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +189,7 @@ private function Init()
|
|||||||
if (!CfgSpawn.static.Load(LogLevel) || Tickrate <= 0)
|
if (!CfgSpawn.static.Load(LogLevel) || Tickrate <= 0)
|
||||||
{
|
{
|
||||||
`ZS_Fatal("Wrong settings, Destroy...");
|
`ZS_Fatal("Wrong settings, Destroy...");
|
||||||
Destroy();
|
SafeDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +199,11 @@ private function Init()
|
|||||||
SpawnListRW = CfgSpawnListRW.static.Load(LogLevel);
|
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);
|
||||||
|
SpawnAtPlayerStartZeds = CfgSpawnAtPlayerStart.static.Load(LogLevel);
|
||||||
|
|
||||||
|
CurrentMap = String(WorldInfo.GetPackageName());
|
||||||
|
GlobalSpawnAtPlayerStart = (CfgSpawnAtPlayerStart.default.Map.Find(CurrentMap) != INDEX_NONE);
|
||||||
|
`ZS_Info("GlobalSpawnAtPlayerStart:" @ GlobalSpawnAtPlayerStart $ GlobalSpawnAtPlayerStart ? "(" $ CurrentMap $ ")" : "");
|
||||||
|
|
||||||
CurrentWave = INDEX_NONE;
|
CurrentWave = INDEX_NONE;
|
||||||
SpecialWave = INDEX_NONE;
|
SpecialWave = INDEX_NONE;
|
||||||
@ -311,6 +328,7 @@ private function SetupWave()
|
|||||||
{
|
{
|
||||||
local Array<String> SpawnListNames;
|
local Array<String> SpawnListNames;
|
||||||
local int WaveTotalAIDef;
|
local int WaveTotalAIDef;
|
||||||
|
local byte BaseWave;
|
||||||
local String WaveTypeInfo;
|
local String WaveTypeInfo;
|
||||||
local S_SpawnEntry SE;
|
local S_SpawnEntry SE;
|
||||||
local EAIType SWType;
|
local EAIType SWType;
|
||||||
@ -379,9 +397,12 @@ private function SetupWave()
|
|||||||
if (UseRegularSpawnList)
|
if (UseRegularSpawnList)
|
||||||
{
|
{
|
||||||
SpawnListNames.AddItem("regular");
|
SpawnListNames.AddItem("regular");
|
||||||
|
BaseWave = KFGIS.WaveNum - CycleWaveSize * (CurrentCycle - 1);
|
||||||
foreach SpawnListRW(SE)
|
foreach SpawnListRW(SE)
|
||||||
if (SE.Wave == KFGIS.WaveNum - CycleWaveSize * (CurrentCycle - 1))
|
if (SE.Wave == BaseWave)
|
||||||
SpawnListCurrent.AddItem(SE);
|
SpawnListCurrent.AddItem(SE);
|
||||||
|
else if (SE.Wave > BaseWave)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UseSpecialSpawnList)
|
if (UseSpecialSpawnList)
|
||||||
@ -426,9 +447,6 @@ private function AdjustSpawnList(out Array<S_SpawnEntry> List)
|
|||||||
Cycle = float(CurrentCycle);
|
Cycle = float(CurrentCycle);
|
||||||
Players = float(PlayerCount());
|
Players = float(PlayerCount());
|
||||||
|
|
||||||
B = float(SE.SpawnCountBase);
|
|
||||||
L = float(SE.SingleSpawnLimitDefault);
|
|
||||||
|
|
||||||
TM = CfgSpawn.default.ZedTotalMultiplier;
|
TM = CfgSpawn.default.ZedTotalMultiplier;
|
||||||
TCM = CfgSpawn.default.SpawnTotalCycleMultiplier;
|
TCM = CfgSpawn.default.SpawnTotalCycleMultiplier;
|
||||||
TPM = CfgSpawn.default.SpawnTotalPlayerMultiplier;
|
TPM = CfgSpawn.default.SpawnTotalPlayerMultiplier;
|
||||||
@ -455,6 +473,9 @@ private function AdjustSpawnList(out Array<S_SpawnEntry> List)
|
|||||||
List[Index].Delay = 0.0f;
|
List[Index].Delay = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
B = float(SE.SpawnCountBase);
|
||||||
|
L = float(SE.SingleSpawnLimitDefault);
|
||||||
|
|
||||||
PawnTotalF = B * (TM + TCM * (Cycle - 1.0f) + TPM * (Players - 1.0f));
|
PawnTotalF = B * (TM + TCM * (Cycle - 1.0f) + TPM * (Players - 1.0f));
|
||||||
PawnLimitF = L * (LM + LCM * (Cycle - 1.0f) + LPM * (Players - 1.0f));
|
PawnLimitF = L * (LM + LCM * (Cycle - 1.0f) + LPM * (Players - 1.0f));
|
||||||
|
|
||||||
@ -498,6 +519,7 @@ private function SpawnEntry(out Array<S_SpawnEntry> SpawnList, int Index)
|
|||||||
local S_SpawnEntry SE;
|
local S_SpawnEntry SE;
|
||||||
local int FreeSpawnSlots, PawnCount, Spawned;
|
local int FreeSpawnSlots, PawnCount, Spawned;
|
||||||
local String Action, Comment, NextSpawn;
|
local String Action, Comment, NextSpawn;
|
||||||
|
local bool SpawnAtPlayerStart;
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
@ -530,7 +552,9 @@ private function SpawnEntry(out Array<S_SpawnEntry> SpawnList, int Index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spawned = SpawnZed(SE.ZedClass, PawnCount, SE.SpawnAtPlayerStart);
|
SpawnAtPlayerStart = (GlobalSpawnAtPlayerStart || (SpawnAtPlayerStartZeds.Find(SE.ZedClass) != INDEX_NONE));
|
||||||
|
|
||||||
|
Spawned = SpawnZed(SE.ZedClass, PawnCount, SpawnAtPlayerStart);
|
||||||
if (Spawned == INDEX_NONE)
|
if (Spawned == INDEX_NONE)
|
||||||
{
|
{
|
||||||
SpawnList[Index].Delay = 5.0f;
|
SpawnList[Index].Delay = 5.0f;
|
||||||
@ -613,9 +637,10 @@ private function Vector PlayerStartLocation()
|
|||||||
return KFGIS.FindPlayerStart(None, 0).Location;
|
return KFGIS.FindPlayerStart(None, 0).Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function int SpawnZed(class<KFPawn_Monster> ZedClass, int PawnCount, bool SpawnAtPlayerStart)
|
private function int SpawnZed(class<KFPawn_Monster> ZedClass, int PawnCount, optional bool SpawnAtPlayerStart = false)
|
||||||
{
|
{
|
||||||
local Array<class<KFPawn_Monster> > CustomSquad;
|
local Array<class<KFPawn_Monster> > CustomSquad;
|
||||||
|
local ESquadType PrevDesiredSquadType;
|
||||||
local Vector SpawnLocation, PlayerStart;
|
local Vector SpawnLocation, PlayerStart;
|
||||||
local KFSpawnVolume SpawnVolume;
|
local KFSpawnVolume SpawnVolume;
|
||||||
local KFPawn_Monster KFPM;
|
local KFPawn_Monster KFPM;
|
||||||
@ -639,12 +664,18 @@ private function int SpawnZed(class<KFPawn_Monster> ZedClass, int PawnCount, boo
|
|||||||
CustomSquad.AddItem(ZedClass);
|
CustomSquad.AddItem(ZedClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrevDesiredSquadType = KFGIS.SpawnManager.DesiredSquadType;
|
||||||
|
KFGIS.SpawnManager.SetDesiredSquadTypeForZedList(CustomSquad);
|
||||||
SpawnVolume = KFGIS.SpawnManager.GetBestSpawnVolume(CustomSquad);
|
SpawnVolume = KFGIS.SpawnManager.GetBestSpawnVolume(CustomSquad);
|
||||||
|
KFGIS.SpawnManager.DesiredSquadType = PrevDesiredSquadType;
|
||||||
|
|
||||||
if (SpawnVolume == None)
|
if (SpawnVolume == None)
|
||||||
{
|
{
|
||||||
return INDEX_NONE;
|
return INDEX_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpawnVolume.VolumeChosenCount++;
|
||||||
|
|
||||||
SpawnLocation = SpawnVolume.Location;
|
SpawnLocation = SpawnVolume.Location;
|
||||||
if (SpawnLocation == PlayerStart)
|
if (SpawnLocation == PlayerStart)
|
||||||
{
|
{
|
||||||
@ -677,6 +708,11 @@ private function int SpawnZed(class<KFPawn_Monster> ZedClass, int PawnCount, boo
|
|||||||
Spawned++;
|
Spawned++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Spawned > 0)
|
||||||
|
{
|
||||||
|
KFGIS.SpawnManager.LastAISpawnVolume = SpawnVolume;
|
||||||
|
}
|
||||||
|
|
||||||
if (CfgSpawn.default.bShadowSpawn && !KFGIS.MyKFGRI.IsBossWave())
|
if (CfgSpawn.default.bShadowSpawn && !KFGIS.MyKFGRI.IsBossWave())
|
||||||
{
|
{
|
||||||
KFGIS.NumAIFinishedSpawning += Spawned;
|
KFGIS.NumAIFinishedSpawning += Spawned;
|
||||||
@ -690,21 +726,55 @@ private function int SpawnZed(class<KFPawn_Monster> ZedClass, int PawnCount, boo
|
|||||||
|
|
||||||
public function NotifyLogin(Controller C)
|
public function NotifyLogin(Controller C)
|
||||||
{
|
{
|
||||||
local ZedSpawnerRepLink RepLink;
|
|
||||||
|
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
RepLink = Spawn(class'ZedSpawnerRepLink', C);
|
CreateRepLink(C);
|
||||||
RepLink.LogLevel = LogLevel;
|
|
||||||
RepLink.CustomZeds = CustomZeds;
|
|
||||||
RepLink.ServerSync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function NotifyLogout(Controller C)
|
public function NotifyLogout(Controller C)
|
||||||
{
|
{
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
return;
|
DestroyRepLink(C);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function CreateRepLink(Controller C)
|
||||||
|
{
|
||||||
|
local ZedSpawnerRepLink RepLink;
|
||||||
|
|
||||||
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
|
if (C == None) return;
|
||||||
|
|
||||||
|
RepLink = Spawn(class'ZedSpawnerRepLink', C);
|
||||||
|
RepLink.LogLevel = LogLevel;
|
||||||
|
RepLink.CustomZeds = CustomZeds;
|
||||||
|
RepLink.ZS = Self;
|
||||||
|
|
||||||
|
RepLinks.AddItem(RepLink);
|
||||||
|
|
||||||
|
RepLink.ServerSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bool DestroyRepLink(Controller C)
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
|
if (C == None) return false;
|
||||||
|
|
||||||
|
for (i = RepLinks.Length - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
if (RepLinks[i].Owner == C)
|
||||||
|
{
|
||||||
|
RepLinks[i].SafeDestroy();
|
||||||
|
RepLinks.Remove(i, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultProperties
|
DefaultProperties
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
class ZedSpawnerRepLink extends ReplicationInfo;
|
class ZedSpawnerRepLink extends ReplicationInfo;
|
||||||
|
|
||||||
var public E_LogLevel LogLevel;
|
var public ZedSpawner ZS;
|
||||||
var public Array<class<KFPawn_Monster> > CustomZeds;
|
var public E_LogLevel LogLevel;
|
||||||
|
var public Array<class<KFPawn_Monster> > CustomZeds;
|
||||||
var private int Recieved;
|
var private int Recieved;
|
||||||
|
|
||||||
replication
|
replication
|
||||||
@ -10,7 +11,11 @@ replication
|
|||||||
LogLevel;
|
LogLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public simulated function bool SafeDestroy() { if (!bPendingDelete) return Destroy(); else return true; }
|
public simulated function bool SafeDestroy()
|
||||||
|
{
|
||||||
|
`ZS_Debug(`Location @ "bPendingDelete:" @ bPendingDelete @ "bDeleteMe" @ bDeleteMe);
|
||||||
|
return (bPendingDelete || bDeleteMe || Destroy());
|
||||||
|
}
|
||||||
|
|
||||||
public reliable client function ClientSync(class<KFPawn_Monster> CustomZed)
|
public reliable client function ClientSync(class<KFPawn_Monster> CustomZed)
|
||||||
{
|
{
|
||||||
@ -40,11 +45,16 @@ public reliable server function ServerSync()
|
|||||||
{
|
{
|
||||||
`ZS_Trace(`Location);
|
`ZS_Trace(`Location);
|
||||||
|
|
||||||
|
if (bPendingDelete || bDeleteMe) return;
|
||||||
|
|
||||||
if (CustomZeds.Length == Recieved || WorldInfo.NetMode == NM_StandAlone)
|
if (CustomZeds.Length == Recieved || WorldInfo.NetMode == NM_StandAlone)
|
||||||
{
|
{
|
||||||
`ZS_Debug("Sync finished");
|
`ZS_Debug("Sync finished");
|
||||||
SyncFinished();
|
SyncFinished();
|
||||||
SafeDestroy();
|
if (!ZS.DestroyRepLink(Controller(Owner)))
|
||||||
|
{
|
||||||
|
SafeDestroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user