Added system to semi-randomly rotate goon spawns across various maps

Removed knight from weekly boss system
This commit is contained in:
Chomp
2025-11-06 13:31:44 +00:00
parent 3a2e1797f2
commit 8ad953a224
3 changed files with 91 additions and 2 deletions
@@ -2895,10 +2895,19 @@
"bossKilla",
"bossKojaniy",
"bossSanitar",
"bossKolontay",
"bossKnight"
"bossKolontay"
],
"resetDay": "Monday"
},
"goonSpawnSystem": {
"enabled": true,
"locationPool": [
"bigmap",
"woods",
"shoreline",
"lighthouse"
],
"spawnChance": 35
},
"replaceScavWith": "assault"
}
@@ -137,6 +137,21 @@ public record BotConfig : BaseConfig
/// </summary>
[JsonPropertyName("replaceScavWith")]
public required WildSpawnType ReplaceScavWith { get; set; }
[JsonPropertyName("goonSpawnSystem")]
public required GoonSpawnSystem GoonSpawnSystem { get; set; }
}
public record GoonSpawnSystem
{
[JsonPropertyName("enabled")]
public bool Enabled { get; set; }
[JsonPropertyName("locationPool")]
public IEnumerable<string> LocationPool { get; set; }
[JsonPropertyName("spawnChance")]
public double SpawnChance { get; set; }
}
public record WeeklyBossSettings
@@ -56,12 +56,15 @@ public class LocationLifecycleService(
protected readonly RagfairConfig RagfairConfig = configServer.GetConfig<RagfairConfig>();
protected readonly HideoutConfig HideoutConfig = configServer.GetConfig<HideoutConfig>();
protected readonly PmcConfig PMCConfig = configServer.GetConfig<PmcConfig>();
protected readonly BotConfig BotConfig = configServer.GetConfig<BotConfig>();
protected readonly LostOnDeathConfig LostOnDeathConfig = configServer.GetConfig<LostOnDeathConfig>();
protected const string Pmc = "pmc";
protected const string Savage = "savage";
protected const string Scav = "scav";
public object botConfig { get; private set; }
/// <summary>
/// Check player type for pmc or scav
/// </summary>
@@ -320,6 +323,11 @@ public class LocationLifecycleService(
return locationBaseClone;
}
if (BotConfig.GoonSpawnSystem.Enabled)
{
AdjustGoonMapSpawns();
}
// Add custom PMCs to map every time its run
pmcWaveGenerator.ApplyWaveChangesToMap(locationBaseClone);
@@ -348,6 +356,63 @@ public class LocationLifecycleService(
return locationBaseClone;
}
/// <summary>
/// Goons will spawn on one map each hour, changing randomly based on a consistent seed made from current utc year + utc hour
/// </summary>
/// <param name="locationBlacklist">LocationIds to always ignore when choosing a spawn</param>
protected void AdjustGoonMapSpawns(HashSet<string>? locationBlacklist = null)
{
locationBlacklist ??= ["hideout", "develop"];
// Reset all maps with goons to 0% spawn, ignore blacklisted locations
var allLocations = databaseService.GetLocations().GetDictionary();
foreach (var (locationId, location) in allLocations)
{
if (!locationBlacklist.Contains(locationId) && location?.Base?.BossLocationSpawn is not null)
{
foreach (var goonSpawn in location.Base.BossLocationSpawn.Where(x => x.BossName == "bossKnight"))
{
goonSpawn.BossChance = 0;
}
}
}
var now = DateTime.UtcNow;
// Create consistent seed for hour (use prime)
var seed = (now.Year * 1009) + now.Hour;
// Init Random class with unique seed
var random = new Random(seed);
// Filter locations pool
var validLocationIds = BotConfig
.GoonSpawnSystem.LocationPool.Where(locationId =>
!locationBlacklist.Contains(locationId)
&& allLocations.TryGetValue(locationId, out var location)
&& location?.Base?.BossLocationSpawn is not null
)
.ToList();
if (validLocationIds.Count == 0)
{
logger.Error("Unable to adjust goon spawn chance, no valid locations found");
return;
}
// Choose a spawn location for goons
var chosenMapId = validLocationIds[random.Next(0, validLocationIds.Count)];
var chosenMap = allLocations[chosenMapId];
// "Where" just incase there's multiple knight spawns for some reason
var goonSpawns = chosenMap.Base.BossLocationSpawn.Where(x => x.BossName == "bossKnight");
foreach (var goonSpawn in goonSpawns)
{
goonSpawn.BossChance = BotConfig.GoonSpawnSystem.SpawnChance;
}
}
/// <summary>
/// Handle client/match/local/end
/// </summary>