Added Boss of the week system

Similar to live where a boss is picked at random and will have a guaranteed spawn on a map. This is indicated with a skull on the map selection screen
Configurable via `config/bot.json/weeklyBoss`
This commit is contained in:
Chomp
2025-06-29 18:58:23 +01:00
parent 4d39a4c819
commit e6b791179b
6 changed files with 126 additions and 1 deletions
@@ -2916,5 +2916,17 @@
"5783c43d2459774bbe137486",
"60b0f6c058e0b0481a09ad11"
]
},
"weeklyBoss": {
"enabled": true,
"bossPool": [
"bossBully",
"bossTagilla",
"bossGluhar",
"bossKilla",
"bossKojaniy",
"bossSanitar",
"bossKolontay"
]
}
}
@@ -109,7 +109,7 @@
"IgnoreMaxBots": true,
"RandomTimeSpawn": false,
"ShowOnTarkovMap": false,
"ShowOnTarkovMapPvE": true,
"ShowOnTarkovMapPvE": false,
"SpawnMode": [
"regular",
"pve"
@@ -106,5 +106,23 @@
return dateToCheck >= eventStartDate && dateToCheck <= eventEndDate;
}
/// <summary>
/// Get the closest monday to passed in datetime
/// </summary>
/// <param name="dateTime">Date to get closest monday of</param>
/// <param name="startDay">Starting day of week - Default = Monday</param>
/// <returns>Monday as DateTime</returns>
public static DateTime GetStartOfWeek(
this DateTime dateTime,
DayOfWeek startDay = DayOfWeek.Monday
)
{
// Calculate difference from current day to Monday
var diff = (7 + (dateTime.DayOfWeek - startDay)) % 7;
// Subtract difference to get date of most recent Monday
return dateTime.AddDays(-1 * diff).Date;
}
}
}
@@ -1144,6 +1144,8 @@ public record Area
public XYZ? Size { get; set; }
}
[EftEnumConverter]
[EftListEnumConverter]
public enum WildSpawnType
{
marksman,
@@ -1,5 +1,6 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -138,6 +139,21 @@ public record BotConfig : BaseConfig
/// </summary>
[JsonPropertyName("botRolesThatMustHaveUniqueName")]
public required HashSet<string> BotRolesThatMustHaveUniqueName { get; set; }
/// <summary>
/// Bot roles that must have a unique name when generated vs other bots in raid
/// </summary>
[JsonPropertyName("weeklyBoss")]
public required WeeklyBossSettings WeeklyBoss { get; set; }
}
public record WeeklyBossSettings
{
[JsonPropertyName("enabled")]
public bool Enabled { get; set; }
[JsonPropertyName("bossPool")]
public List<WildSpawnType> BossPool { get; set; }
}
/// <summary>
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -126,6 +127,82 @@ public class PostDbLoadService(
var currentSeason = _seasonalEventService.GetActiveWeatherSeason();
_raidWeatherService.GenerateWeather(currentSeason);
if (_botConfig.WeeklyBoss.Enabled)
{
var chosenBoss = GetWeeklyBoss(_botConfig.WeeklyBoss.BossPool);
FlagMapAsGuaranteedBoss(chosenBoss);
}
}
/// <summary>
/// Choose a boss that will spawn at 100% on a map from a predefined collection of bosses
/// </summary>
/// <param name="bosses">Pool of bosses to pick from</param>
/// <returns>Boss to spawn for this week</returns>
protected WildSpawnType GetWeeklyBoss(List<WildSpawnType> bosses)
{
// Get closest monday to today
var startOfWeek = DateTime.Today.GetStartOfWeek();
// Create a consistent seed for the week using the year and the day of the year of above monday chosen
// This results in seed being identical for the week
var seed = startOfWeek.Year * 1000 + startOfWeek.DayOfYear;
// Init Random class with unique seed
var random = new Random(seed);
// First number generated by random.Next() will always be the same because of the seed
return bosses[random.Next(0, bosses.Count)];
}
/// <summary>
/// Given the provided boss, flag them as 100% spawn and add skull to the map they spawn on
/// </summary>
/// <param name="boss">Boss to flag</param>
protected void FlagMapAsGuaranteedBoss(WildSpawnType boss)
{
// Get the corresponding map for the provided boss
var locations = _databaseService.GetLocations();
Location? location;
switch (boss)
{
case WildSpawnType.bossBully:
location = locations.Bigmap;
break;
case WildSpawnType.bossGluhar:
location = locations.RezervBase;
break;
case WildSpawnType.bossKilla:
location = locations.Interchange;
break;
case WildSpawnType.bossKojaniy:
location = locations.Woods;
break;
case WildSpawnType.bossSanitar:
location = locations.Shoreline;
break;
case WildSpawnType.bossKolontay:
location = locations.TarkovStreets;
break;
default:
_logger.Warning($"Unknown boss type: {boss}. Unable to set as weekly. Skipping");
return;
}
var bossSpawn = location.Base.BossLocationSpawn.FirstOrDefault(x =>
x.BossName == boss.ToString()
);
if (bossSpawn is null)
{
_logger.Warning($"Boss: {boss} not found on map, unable to set as weekly. Skipping");
return;
}
_logger.Debug($"{boss} is boss of the week");
bossSpawn.BossChance = 100;
bossSpawn.ShowOnTarkovMap = true;
bossSpawn.ShowOnTarkovMapPvE = true;
}
private void MergeCustomHideoutAreas()