Skip to content

Commit

Permalink
[fix] remove custom processing around boss/scav spawns (#289)
Browse files Browse the repository at this point in the history
This removes the custom code we have around boss spawning since we
probably have no business handling that ourselves and so that we can be
more inline with SPT and mods.
Tested bosses and scavs are spawning fine, no cultist during the day.
  • Loading branch information
paulov-t authored Apr 26, 2024
2 parents d210201 + 170a726 commit 0b62510
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 107 deletions.
58 changes: 58 additions & 0 deletions Source/AkiSupport/Custom/BossSpawnChancePatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using EFT;
using StayInTarkov;
using System.Linq;
using System.Reflection;

namespace Aki.Custom.Patches
{
/// <summary>
/// Created by: SPT-Aki
/// Link: https://dev.sp-tarkov.com/SPT-AKI/Modules/src/branch/master/project/Aki.Custom/Patches/BossSpawnChancePatch.cs
/// Boss spawn chance is 100%, all the time, this patch adjusts the chance to the maps boss wave value
/// </summary>
public class BossSpawnChancePatch : ModulePatch
{
private static float[] _bossSpawnPercent;

protected override MethodBase GetTargetMethod()
{
var desiredType = typeof(LocalGame);
var desiredMethod = desiredType
.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
.SingleOrDefault(IsTargetMethod);

Logger.LogDebug($"{this.GetType().Name} Type: {desiredType.Name}");
Logger.LogDebug($"{this.GetType().Name} Method: {desiredMethod?.Name ?? "NOT FOUND"}");

return desiredMethod;
}

private static bool IsTargetMethod(MethodInfo mi)
{
var parameters = mi.GetParameters();
return (parameters.Length == 2
&& parameters[0].Name == "wavesSettings"
&& parameters[1].Name == "bossLocationSpawn");
}

[PatchPrefix]
private static void PatchPrefix(BossLocationSpawn[] bossLocationSpawn)
{
_bossSpawnPercent = bossLocationSpawn.Select(s => s.BossChance).ToArray();
}

[PatchPostfix]
private static void PatchPostfix(ref BossLocationSpawn[] __result)
{
if (__result.Length != _bossSpawnPercent.Length)
{
return;
}

for (var i = 0; i < _bossSpawnPercent.Length; i++)
{
__result[i].BossChance = _bossSpawnPercent[i];
}
}
}
}
113 changes: 6 additions & 107 deletions Source/Coop/SITGameModes/CoopSITGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ InputTree inputTree

// ---------------------------------------------------------------------------------
// Non Waves Scenario setup
WildSpawnWave[] waves = FixScavWaveSettings(wavesSettings, location.waves);
WildSpawnWave[] waves = LocalGame.smethod_7(wavesSettings, location.waves);
coopGame.nonWavesSpawnScenario_0 = NonWavesSpawnScenario.smethod_0(coopGame, location, coopGame.PBotsController);
coopGame.nonWavesSpawnScenario_0.ImplementWaveSettings(wavesSettings);

Expand All @@ -170,14 +170,13 @@ InputTree inputTree
coopGame.wavesSpawnScenario_0 = WavesSpawnScenario.smethod_0(
coopGame.gameObject
, waves
, new Action<BotSpawnWave>((wave) => coopGame.PBotsController.ActivateBotsByWave(wave))
, new Action<BotSpawnWave>(coopGame.PBotsController.ActivateBotsByWave)
, location);

// ---------------------------------------------------------------------------------
// Setup Boss Wave Manager
coopGame.BossWaves = coopGame.FixBossWaveSettings(wavesSettings, location);
var bosswavemanagerValue = BossWaveManager.smethod_0(coopGame.BossWaves, new Action<BossLocationSpawn>((bossWave) => { coopGame.PBotsController.ActivateBotsByWave(bossWave); }));
coopGame.BossWaveManager = bosswavemanagerValue;
coopGame.BossWaves = LocalGame.smethod_8(wavesSettings, location.BossLocationSpawn);
coopGame.BossWaveManager = BossWaveManager.smethod_0(coopGame.BossWaves, new Action<BossLocationSpawn>(coopGame.PBotsController.ActivateBotsByWave));

coopGame.func_1 = (player) => GamePlayerOwner.Create<GamePlayerOwner>(player, inputTree, insurance, backEndSession, commonUI, preloaderUI, gameUI, coopGame.GameDateTime, location);

Expand All @@ -191,8 +190,6 @@ InputTree inputTree
coopGame.CreateCoopGameComponent();
SITGameComponent.GetCoopGameComponent().LocalGameInstance = coopGame;



// ---------------------------------------------------------------------------------
// Create GameClient(s)
switch (SITMatchmaking.SITProtocol)
Expand Down Expand Up @@ -412,29 +409,6 @@ private IEnumerator ArmoredTrainTimeSync()
}
}


public static WildSpawnWave[] FixScavWaveSettings(WavesSettings wavesSettings, WildSpawnWave[] waves)
{
Logger.LogDebug($"{nameof(CoopSITGame)}:{nameof(FixScavWaveSettings)}");

foreach (WildSpawnWave wildSpawnWave in waves)
{
wildSpawnWave.slots_min = wavesSettings.BotAmount == EBotAmount.NoBots ? 0 : 1;
wildSpawnWave.slots_max = wavesSettings.BotAmount == EBotAmount.NoBots ? 0 : Math.Max(1, wildSpawnWave.slots_max);
if (wavesSettings.IsTaggedAndCursed && wildSpawnWave.WildSpawnType == WildSpawnType.assault)
{
wildSpawnWave.WildSpawnType = WildSpawnType.cursedAssault;
}
if (wavesSettings.IsBosses)
{
wildSpawnWave.time_min += 5;
wildSpawnWave.time_max += 27;
}
wildSpawnWave.BotDifficulty = ToBotDifficulty(wavesSettings.BotDifficulty);
}
return waves;
}

public static BotDifficulty ToBotDifficulty(EBotDifficulty botDifficulty)
{
return botDifficulty switch
Expand All @@ -454,73 +428,6 @@ public static BotDifficulty SelectRandomBotDifficulty()
return (BotDifficulty)values.GetValue(UnityEngine.Random.Range(0, values.Length));
}

private static int[] CultistSpawnTime = new[] { 6, 22 };

private static bool CanSpawnCultist(int hour)
{
return hour <= CultistSpawnTime[0] || hour >= CultistSpawnTime[1];
}

public BossLocationSpawn[] FixBossWaveSettings(WavesSettings wavesSettings, LocationSettingsClass.Location location)
{
#if DEBUG
Logger.LogDebug($"{nameof(FixBossWaveSettings)}:{location.ToJson()}");
#endif

var bossLocationSpawns = location.BossLocationSpawn;
TimeSpan CurrentGameTime = GameDateTime.Calculate().TimeOfDay;
if (!wavesSettings.IsBosses)
{
Logger.LogDebug($"{nameof(CoopSITGame)}:{nameof(FixBossWaveSettings)}: Bosses are disabled");
return new BossLocationSpawn[0];
}
foreach (BossLocationSpawn bossLocationSpawn in bossLocationSpawns)
{
#if DEBUG
Logger.LogDebug($"{nameof(FixBossWaveSettings)}:===BEFORE===");
Logger.LogDebug($"{nameof(FixBossWaveSettings)}:{bossLocationSpawn.ToJson()}");
#endif

if (!CanSpawnCultist(CurrentGameTime.Hours) && bossLocationSpawn.BossName.Contains("sectant"))
{
Logger.LogDebug($"Block spawn of Sectant (Cultist) in day time in hour {CurrentGameTime.Hours}!");
bossLocationSpawn.BossChance = 0f;
}

//ArchangelWTF: boss types like 'arenaFighterEvent' can have multiple values, split these out and take the first value.
//We could maybe do some fancy randomization here at some point to get a number in between the two values, but for now this works.
if (bossLocationSpawn.BossEscortAmount.Contains(","))
bossLocationSpawn.BossEscortAmount = bossLocationSpawn.BossEscortAmount.Split(',')[0];

int EscortAmount = Convert.ToInt32(bossLocationSpawn.BossEscortAmount);

if (bossLocationSpawn.Supports == null && !string.IsNullOrEmpty(bossLocationSpawn.BossEscortType) && EscortAmount > 0)
{
Logger.LogDebug($"bossLocationSpawn.Supports is Null. Attempt to create them.");

Enum.TryParse<WildSpawnType>(bossLocationSpawn.BossEscortType, out var EscortType);

bossLocationSpawn.Supports = new WildSpawnSupports[EscortAmount];

for (int i = 0; i < EscortAmount; i++)
{
bossLocationSpawn.Supports[i] = new WildSpawnSupports
{
BossEscortDifficult = new[] { bossLocationSpawn.BossEscortDifficult },
BossEscortAmount = 1,
BossEscortType = EscortType
};
}
}

#if DEBUG
Logger.LogDebug($"{nameof(FixBossWaveSettings)}:===AFTER===");
Logger.LogDebug($"{nameof(FixBossWaveSettings)}:{bossLocationSpawn.ToJson()}");
#endif
}
return bossLocationSpawns;
}

public Dictionary<string, EFT.Player> Bots { get; } = new();

private async Task<LocalPlayer> CreatePhysicalBot(Profile profile, Vector3 position)
Expand All @@ -533,15 +440,7 @@ private async Task<LocalPlayer> CreatePhysicalBot(Profile profile, Vector3 posit
Logger.LogDebug("Block spawn of Bot. Max Bot Count has been reached!");
return null;
}

if (!CanSpawnCultist(GameDateTime.Calculate().TimeOfDay.Hours) && profile.Info != null && profile.Info.Settings != null
&& (profile.Info.Settings.Role == WildSpawnType.sectantPriest || profile.Info.Settings.Role == WildSpawnType.sectantWarrior)
)
{
Logger.LogDebug("Block spawn of Sectant (Cultist) in day time!");
return null;
}
Logger.LogDebug($"CreatePhysicalBot: {profile.ProfileId}");
Logger.LogDebug($"CreatePhysicalBot: {profile.ProfileId} role={profile.Info?.Settings?.Role}");

LocalPlayer botPlayer;
if (!Status.IsRunned())
Expand Down Expand Up @@ -1081,7 +980,7 @@ public override IEnumerator vmethod_4(float startDelay, BotControllerSettings co
, false // controllerSettings.IsScavWars
, true
, false // online
, GameDateTime.DateTime_0.Hour > 21 // have sectants
, this.BossWaveManager.HaveSectants
, Singleton<GameWorld>.Instance
, Location_0.OpenZones)
;
Expand Down
1 change: 1 addition & 0 deletions Source/StayInTarkovPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ private void EnableSPPatches_PlayerHealth(BepInEx.Configuration.ConfigFile confi
private static void EnableSPPatches_Bots(BepInEx.Configuration.ConfigFile config)
{
new CoreDifficultyPatch().Enable();
new BossSpawnChancePatch().Enable();
new BotDifficultyPatch().Enable();
new BotSettingsRepoClassIsFollowerFixPatch().Enable();
new BotSelfEnemyPatch().Enable();
Expand Down

0 comments on commit 0b62510

Please sign in to comment.