using SPT.Reflection.Patching; using EFT; using System; using Comfort.Common; using System.Reflection; using SPT.PrePatch; using SPT.Custom.CustomAI; using HarmonyLib; namespace SPT.Custom.Patches { public class CustomAiPatch : ModulePatch { private static readonly PmcFoundInRaidEquipment pmcFoundInRaidEquipment = new PmcFoundInRaidEquipment(Logger); private static readonly AIBrainSpawnWeightAdjustment aIBrainSpawnWeightAdjustment = new AIBrainSpawnWeightAdjustment(Logger); protected override MethodBase GetTargetMethod() { return AccessTools.Method(typeof(StandartBotBrain), nameof(StandartBotBrain.Activate)); } /// /// Get a randomly picked wildspawntype from server and change PMC bot to use it, this ensures the bot is generated with that random type altering its behaviour /// Postfix will adjust it back to original type /// /// state to save for postfix to use later /// /// botOwner_0 property [PatchPrefix] private static bool PatchPrefix(out WildSpawnType __state, StandartBotBrain __instance, BotOwner ___botOwner_0) { var player = Singleton.Instance.MainPlayer; ___botOwner_0.Profile.Info.Settings.Role = FixAssaultGroupPmcsRole(___botOwner_0); __state = ___botOwner_0.Profile.Info.Settings.Role; // Store original type in state param to allow access in PatchPostFix() try { string currentMapName = GetCurrentMap(); if (AiHelpers.BotIsPlayerScav(__state, ___botOwner_0.Profile.Info.Nickname)) { ___botOwner_0.Profile.Info.Settings.Role = aIBrainSpawnWeightAdjustment.GetRandomisedPlayerScavType(___botOwner_0, currentMapName); return true; // Do original } if (AiHelpers.BotIsNormalAssaultScav(__state, ___botOwner_0)) { ___botOwner_0.Profile.Info.Settings.Role = aIBrainSpawnWeightAdjustment.GetAssaultScavWildSpawnType(___botOwner_0, currentMapName); return true; // Do original } if (AiHelpers.BotIsSptPmc(__state, ___botOwner_0)) { // Bot has inventory equipment if (___botOwner_0.Profile?.Inventory?.Equipment != null) { pmcFoundInRaidEquipment.ConfigurePMCFindInRaidStatus(___botOwner_0); } ___botOwner_0.Profile.Info.Settings.Role = aIBrainSpawnWeightAdjustment.GetPmcWildSpawnType(___botOwner_0, ___botOwner_0.Profile.Info.Settings.Role, currentMapName); } } catch (Exception ex) { Logger.LogError($"Error running CustomAiPatch PatchPrefix(): {ex.Message}"); Logger.LogError(ex.StackTrace); } return true; // Do original } /// /// the client sometimes replaces PMC roles with 'assaultGroup', give PMCs their original role back (sptBear/sptUsec) /// /// WildSpawnType private static WildSpawnType FixAssaultGroupPmcsRole(BotOwner botOwner) { if (botOwner.Profile.Info.IsStreamerModeAvailable && botOwner.Profile.Info.Settings.Role == WildSpawnType.assaultGroup) { Logger.LogError($"Broken PMC found: {botOwner.Profile.Nickname}, was {botOwner.Profile.Info.Settings.Role}"); // Its a PMC, figure out what the bot originally was and return it return botOwner.Profile.Info.Side == EPlayerSide.Bear ? (WildSpawnType)SPTBotsPrePatcher.sptBearValue : (WildSpawnType)SPTBotsPrePatcher.sptUsecValue; } // Not broken pmc, return original role return botOwner.Profile.Info.Settings.Role; } /// /// Revert prefix change, get bots type back to what it was before changes /// /// Saved state from prefix patch /// botOwner_0 property [PatchPostfix] private static void PatchPostFix(WildSpawnType __state, BotOwner ___botOwner_0) { if (AiHelpers.BotIsSptPmc(__state, ___botOwner_0)) { // Set spt bot bot back to original type ___botOwner_0.Profile.Info.Settings.Role = __state; } else if (AiHelpers.BotIsPlayerScav(__state, ___botOwner_0.Profile.Info.Nickname)) { // Set pscav back to original type ___botOwner_0.Profile.Info.Settings.Role = __state; } } private static string GetCurrentMap() { var gameWorld = Singleton.Instance; return gameWorld.MainPlayer.Location; } } }