Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to SPT 3.10 #40

Merged
merged 17 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ You're no longer the only PMC running around placing markers and collecting ques
* [Waypoints](https://hub.sp-tarkov.com/files/file/1119-waypoints-expanded-bot-patrols-and-navmesh/)

**Highly Recommended:**
* [SAIN](https://hub.sp-tarkov.com/files/file/1062-sain-2-0-solarint-s-ai-modifications-full-ai-combat-system-replacement/) (3.0.4 or later recommended)
* [Looting Bots](https://hub.sp-tarkov.com/files/file/1096-looting-bots/) (1.3.5 or later recommended)
* [SAIN](https://hub.sp-tarkov.com/files/file/1062-sain-2-0-solarint-s-ai-modifications-full-ai-combat-system-replacement/) (3.2.0 or later recommended)
* [Looting Bots](https://hub.sp-tarkov.com/files/file/1096-looting-bots/) (1.4.0 or later recommended)

**NOT compatible with:**
* [AI Limit](https://hub.sp-tarkov.com/files/file/793-ai-limit/) or any other mods that disable AI in a similar manner. This mod relies on the AI being active throughout the entire map. **Starting with 0.2.10, Questing Bots has its own AI Limiter feature.** Please see the tab below for more information.
* [Traveler](https://hub.sp-tarkov.com/files/file/1212-traveler/) (You MUST use another mod like [SWAG + DONUTS](https://hub.sp-tarkov.com/files/file/878-swag-donuts-dynamic-spawn-waves-and-custom-spawn-points/) to manage bot spawning when using this mod. Otherwise, bots will spawn right in front of you.)

**Compatible with:**
* [SWAG + DONUTS](https://hub.sp-tarkov.com/files/file/878-swag-donuts-dynamic-spawn-waves-and-custom-spawn-points/)
* [Late to the Party](https://hub.sp-tarkov.com/files/file/1099-late-to-the-party/) (if **bot_spawns.enabled=true** in this mod, ensure **adjust_bot_spawn_chances.adjust_pmc_conversion_chances=false** in LTTP)
* [Late to the Party](https://hub.sp-tarkov.com/files/file/1099-late-to-the-party/)
* **Fika** (Requires client version 0.9.8962.33287 or later)

**NOTE: Please disable the bot-spawning system in this mod if you're using other mods that manage spawning! Otherwise, there will be too many bots on the map. The bot-spawning system in this mod will be automatically disabled** if any of the following mods are detected:
Expand Down Expand Up @@ -176,16 +176,11 @@ Since normal AI Limit mods will disable bots that are questing (which will preve
**Main Options:**
* **enabled**: Completely enable or disable all featues of this mod.
* **debug.enabled**: Enable debug mode.
* **debug.scav_cooldown_time**: Cooldown timer (in seconds) after a Scav raid ends before you're allowed to start another one. This is **1500** by default, which is the same as the base game.
* **debug.full_length_scav_raids**: If **true**, Scav raids will always be full-length.
* **debug.free_labs_access**: If **true**, Labs cards are no longer required to enter Labs, and you're also allowed to do Scav runs in Labs.
* **debug.always_spawn_pmcs**: If **true**, PMC's will spawn even when you select "None" for the amount of bots when starting a raid.
* **debug.always_spawn_pscavs**: If **true**, player Scavs will spawn even when you select "None" for the amount of bots when starting a raid.
* **debug.always_have_airdrops**: If **true**, an airdrop will appear at the beginning of all raids for applicable maps
* **debug.show_zone_outlines**: If **true**, EFT quest zones will be outlined in light blue. Target locations for each zone will have light-blue spherical outlines.
* **debug.show_failed_paths**: If **true**, whenever a bot gets stuck its target path will be drawn in red.
* **debug.show_door_interaction_test_points**: If **true**, the positions tested when determining where bots should travel to unlock doors will have spherical outlines. If the a valid NavMesh position cannot be found for the test point, the outline color will be white. If a valid NavMesh position is found but the bot cannot access that point, the outline color will be yellow. If a valid NavMesh position is found and the bot can access that point, the outline color will be magenta. The position selected for the bot will be shown with a green outline.
* **debug.friendly_pmcs**: Make all PMC's friendly with you during PMC raids. This is **false** by default.
* **max_calc_time_per_frame_ms**: The maximum amount of time (in milliseconds) the mod is allowed to run quest-generation and PMC-spawning procedures per frame. By default this is set to **5** ms, and delays of <15 ms are basically imperceptible.
* **chance_of_being_hostile_toward_bosses.scav**: The chance that Scavs will be hostile toward all bosses on the map. This is **0%** by default.
* **chance_of_being_hostile_toward_bosses.pscav**: The chance that player Scavs will be hostile toward all bosses on the map even if the bosses aren't hostile toward them (i.e. Rogues are not initially hostile toward player Scavs). This is **20%** by default.
Expand Down Expand Up @@ -338,6 +333,11 @@ Since normal AI Limit mods will disable bots that are questing (which will preve
* **bot_spawns.limit_initial_boss_spawns.max_initial_bosses**: The maximum number of bosses that are allowed to spawn at the beginning of the raid (including Raiders and Rogues). After this number is reached, all remaining initial boss spawns will be canceled. If this number is too high, few Scavs will be able to spawn after the initial PMC spawns. This is **14** by default.
* **bot_spawns.limit_initial_boss_spawns.max_initial_rogues**: The maximum number of Rogues that are allowed to spawn at the beginning of the raid. After this number is reached, all remaining initial Rogue spawns will be canceled. If this number is too high, few Scavs will be able to spawn after the initial PMC spawns. This is **10** by default.
* **bot_spawns.max_alive_bots**: The maximum number of PMC's and player Scavs (combined) that can be alive at the same time on each map. This only applies to PMC's and player Scavs generated by this mod; it doesn't apply to bots spawned by other mods or for Scavs converted to PMC's or player Scavs automatically by SPT.
* **bot_spawns.pmc_hostility_adjustments.enabled**: If this mod should override EFT's hostility chances for PMC bots. This is **true** by default.
* **bot_spawns.pmc_hostility_adjustments.pmcs_always_hostile_against_pmcs**: Makes PMC's always hostile against other PMC's. This is **true** by default.
* **bot_spawns.pmc_hostility_adjustments.pmcs_always_hostile_against_scavs**: Makes PMC's always hostile against Scavs and vice versa. This is **true** by default.
* **bot_spawns.pmc_hostility_adjustments.global_scav_enemy_chance**: Sets the global chance that PMC's will be hostile toward Scavs. However, EFT does not use this setting in many maps. This is **100** by default.
* **bot_spawns.pmc_hostility_adjustments.pmc_enemy_roles**: Makes PMC's always hostile toward bots with these roles.
* **bot_spawns.pmcs.xxx**: The settings to apply to PMC spawns (see below for details).
* **bot_spawns.player_scavs.xxx**: The settings to apply to player Scav spawns (see below for details).
* **adjust_pscav_chance.enabled**: If the chances that Scavs are converted to player Scavs should be adjusted throughout the raid. This is only used if **bot_spawns.enabled=false** or **bot_spawns.player_scavs.enabled=false**, and it is **true** by default.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ namespace SPTQuestingBots_CustomBotGenExample
{
public class ParalyzeAction : CustomLogic
{
protected GClass134 baseAction { get; private set; } = null;
protected GClass156 baseAction { get; private set; } = null;

public ParalyzeAction(BotOwner _BotOwner) : base(_BotOwner)
{
// This doesn't quite achieve "paralysis", but it's probably good enough
baseAction = GClass459.CreateNode(BotLogicDecision.standBy, BotOwner);
baseAction = GClass507.CreateNode(BotLogicDecision.standBy, BotOwner);
baseAction.Awake();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ protected bool MustHeal()
}
if (neededToHeal)
{
LoggingController.LogInfo("Bot " + BotOwner.GetText() + " is now healed.");
LoggingController.LogDebug("Bot " + BotOwner.GetText() + " is now healed.");
}

mustHealTimer.Reset();
Expand All @@ -90,7 +90,7 @@ protected bool IsAbleBodied()
}
if (!wasAbleBodied)
{
LoggingController.LogInfo("Bot " + BotOwner.GetText() + " is now able-bodied.");
LoggingController.LogDebug("Bot " + BotOwner.GetText() + " is now able-bodied.");
}

notAbleBodiedTimer.Reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using DrakiaXYZ.BigBrain.Brains;
using EFT;
using EFT.Interactive;
using HarmonyLib;
using SPTQuestingBots.Controllers;
using SPTQuestingBots.Helpers;
using UnityEngine;
Expand All @@ -19,7 +18,7 @@ namespace SPTQuestingBots.BehaviorExtensions
public abstract class CustomLogicDelayedUpdate : CustomLogic
{
protected BotLogic.Objective.BotObjectiveManager ObjectiveManager { get; private set; }
protected GClass134 baseAction { get; private set; } = null;
protected GClass156 baseAction { get; private set; } = null;
protected static int updateInterval { get; private set; } = 100;

private Stopwatch updateTimer = Stopwatch.StartNew();
Expand All @@ -28,7 +27,7 @@ public abstract class CustomLogicDelayedUpdate : CustomLogic
private float sprintDelayTime = 0;

// Find by CreateNode(BotLogicDecision type, BotOwner bot) -> case BotLogicDecision.simplePatrol -> private gclass object
private GClass327 baseSteeringLogic = new GClass327();
private GClass370 baseSteeringLogic = new GClass370();

protected double ActionElpasedTime => actionElapsedTime.ElapsedMilliseconds / 1000.0;
protected double ActionElapsedTimeRemaining => Math.Max(0, ObjectiveManager.MinElapsedActionTime - ActionElpasedTime);
Expand Down Expand Up @@ -71,7 +70,7 @@ public void RestartActionElapsedTime()
actionElapsedTime.Restart();
}

public void SetBaseAction(GClass134 _baseAction)
public void SetBaseAction(GClass156 _baseAction)
{
baseAction = _baseAction;
baseAction.Awake();
Expand Down
25 changes: 13 additions & 12 deletions bepinex_dev/SPTQuestingBots/BotLogic/BotMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public bool TrySetIgnoreHearing(float duration, bool value)
return false;
}

LoggingController.LogInfo("Instructing " + botOwner.GetText() + " to " + (value ? "" : "not ") + "ignore hearing for " + duration + "s");
LoggingController.LogDebug("Instructing " + botOwner.GetText() + " to " + (value ? "" : "not ") + "ignore hearing for " + duration + "s");

return true;
}
Expand Down Expand Up @@ -190,7 +190,7 @@ public bool TryPreventBotFromLooting(float duration)

if (LootingBots.LootingBotsInterop.TryPreventBotFromLooting(botOwner, duration))
{
LoggingController.LogInfo("Preventing " + botOwner.GetText() + " from looting");
LoggingController.LogDebug("Preventing " + botOwner.GetText() + " from looting");

return true;
}
Expand All @@ -202,6 +202,7 @@ public bool TryPreventBotFromLooting(float duration)
return false;
}

private static string sainPluginId = "me.sol.sain";
public bool TryForceBotToScanLoot()
{
if (!canUseLootingBotsInterop)
Expand All @@ -215,7 +216,7 @@ public bool TryForceBotToScanLoot()
// reduce how long bots unnecessarily spend in SAIN's layers.
if (canUseSAINInterop)
{
Version sainVersion = Chainloader.PluginInfos["me.sol.sain"].Metadata.Version;
Version sainVersion = Chainloader.PluginInfos[sainPluginId].Metadata.Version;
Version maxVersionForResettingDecisions = new Version(ConfigController.Config.Questing.BotQuestingRequirements.BreakForLooting.MaxSainVersionForResettingDecisions);

if ((sainVersion.CompareTo(maxVersionForResettingDecisions) < 0) && !SAIN.Plugin.SAINInterop.TryResetDecisionsForBot(botOwner))
Expand All @@ -226,7 +227,7 @@ public bool TryForceBotToScanLoot()

if (LootingBots.LootingBotsInterop.TryForceBotToScanLoot(botOwner))
{
LoggingController.LogInfo("Instructing " + botOwner.GetText() + " to loot now");
LoggingController.LogDebug("Instructing " + botOwner.GetText() + " to loot now");

return true;
}
Expand All @@ -253,7 +254,7 @@ public bool TryInstructBotToExtract()
return false;
}

LoggingController.LogInfo("Instructing " + botOwner.GetText() + " to extract now");
LoggingController.LogDebug("Instructing " + botOwner.GetText() + " to extract now");

foreach (BotOwner follower in HiveMind.BotHiveMindMonitor.GetFollowers(botOwner))
{
Expand All @@ -264,7 +265,7 @@ public bool TryInstructBotToExtract()

if (SAIN.Plugin.SAINInterop.TryExtractBot(follower))
{
LoggingController.LogInfo("Instructing follower " + follower.GetText() + " to extract now");
LoggingController.LogDebug("Instructing follower " + follower.GetText() + " to extract now");
}
else
{
Expand Down Expand Up @@ -375,7 +376,7 @@ public bool MustHeal(bool writeToLog)
{
if (writeToLog)
{
LoggingController.LogInfo("Bot " + botOwner.GetText() + " needs to heal");
LoggingController.LogDebug("Bot " + botOwner.GetText() + " needs to heal");
}
return true;
}
Expand All @@ -395,7 +396,7 @@ public bool IsAbleBodied(bool writeToLog)
{
if (writeToLog)
{
LoggingController.LogInfo("Bot " + botOwner.GetText() + " needs to drink");
LoggingController.LogDebug("Bot " + botOwner.GetText() + " needs to drink");
}
return false;
}
Expand All @@ -405,7 +406,7 @@ public bool IsAbleBodied(bool writeToLog)
{
if (writeToLog)
{
LoggingController.LogInfo("Bot " + botOwner.GetText() + " needs to eat");
LoggingController.LogDebug("Bot " + botOwner.GetText() + " needs to eat");
}
return false;
}
Expand All @@ -429,7 +430,7 @@ public bool IsAbleBodied(bool writeToLog)
{
if (writeToLog)
{
LoggingController.LogInfo("Bot " + botOwner.GetText() + " cannot heal");
LoggingController.LogDebug("Bot " + botOwner.GetText() + " cannot heal");
}
return false;
}
Expand All @@ -439,7 +440,7 @@ public bool IsAbleBodied(bool writeToLog)
{
if (writeToLog)
{
LoggingController.LogInfo("Bot " + botOwner.GetText() + " is overweight");
LoggingController.LogDebug("Bot " + botOwner.GetText() + " is overweight");
}
return false;
}
Expand Down Expand Up @@ -511,7 +512,7 @@ public bool ShouldCheckForLoot(float minTimeBetweenLooting)
{
if (!hasFoundLoot)
{
LoggingController.LogInfo("Bot " + botOwner.GetText() + " has found loot");
LoggingController.LogDebug("Bot " + botOwner.GetText() + " has found loot");
}

NextLootCheckDelay = ConfigController.Config.Questing.BotQuestingRequirements.BreakForLooting.MinTimeBetweenLootingEvents;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal class BossRegroupAction : BehaviorExtensions.GoToPositionAbstractAction

public BossRegroupAction(BotOwner _BotOwner) : base(_BotOwner, 100)
{
SetBaseAction(GClass459.CreateNode(BotLogicDecision.simplePatrol, BotOwner));
SetBaseAction(GClass507.CreateNode(BotLogicDecision.simplePatrol, BotOwner));
}

public override void Start()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal class FollowerRegroupAction : BehaviorExtensions.GoToPositionAbstractAc

public FollowerRegroupAction(BotOwner _BotOwner) : base(_BotOwner, 100)
{
SetBaseAction(GClass459.CreateNode(BotLogicDecision.simplePatrol, BotOwner));
SetBaseAction(GClass507.CreateNode(BotLogicDecision.simplePatrol, BotOwner));
}

public override void Start()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static void Clear()
sensors.Clear();
}

private void Update()
protected void Update()
{
if (!canUpdate())
{
Expand Down
8 changes: 5 additions & 3 deletions bepinex_dev/SPTQuestingBots/BotLogic/LogicLayerMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void Init(BotOwner _botOwner, string _layerName, float _maxLayerSearchTim
Init(_botOwner, _layerName);
}

private void Update()
protected void Update()
{
if ((botOwner == null) || (LayerName == null))
{
Expand Down Expand Up @@ -127,7 +127,8 @@ public static ReadOnlyCollection<AICoreLayerClass<BotLogicDecision>> GetBrainLay

// Find the field that stores the list of brain layers assigned to the bot
Type aICoreStrategyClassType = typeof(AICoreStrategyAbstractClass<BotLogicDecision>);
FieldInfo layerListField = aICoreStrategyClassType.GetField("list_0", BindingFlags.NonPublic | BindingFlags.Instance);

FieldInfo layerListField = AccessTools.Field(aICoreStrategyClassType, "list_0");
if (layerListField == null)
{
LoggingController.LogError("Could not find brain layer list in type " + aICoreStrategyClassType.FullName);
Expand Down Expand Up @@ -185,6 +186,7 @@ public static bool IsBrainLayerActiveForBot(BotOwner botOwner, string layerName)
return brainLayer.IsActive;
}

private static string bigBrainCustomLayerWrapperTypeName = "DrakiaXYZ.BigBrain.Internal.CustomLayerWrapper";
public static CustomLayer GetExternalCustomLayer(AICoreLayerClass<BotLogicDecision> layer)
{
if (layer == null)
Expand All @@ -199,7 +201,7 @@ public static CustomLayer GetExternalCustomLayer(AICoreLayerClass<BotLogicDecisi
return null;
}

Type customLayerWrapperType = bigBrainAssembly.GetType("DrakiaXYZ.BigBrain.Internal.CustomLayerWrapper", false);
Type customLayerWrapperType = bigBrainAssembly.GetType(bigBrainCustomLayerWrapperTypeName, false);
if (customLayerWrapperType == null)
{
LoggingController.LogError("Could not find CustomLayerWrapper type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class AmbushAction : BehaviorExtensions.GoToPositionAbstractAction

public AmbushAction(BotOwner _BotOwner) : base(_BotOwner, 100)
{
SetBaseAction(GClass459.CreateNode(BotLogicDecision.holdPosition, BotOwner));
SetBaseAction(GClass507.CreateNode(BotLogicDecision.holdPosition, BotOwner));
}

public AmbushAction(BotOwner _BotOwner, bool _allowedToIgnoreHearing) : this(_BotOwner)
Expand Down
Loading