From 761d6c339dae0fcfdc0b9fe05d6b33eabd027772 Mon Sep 17 00:00:00 2001 From: Dev Date: Sun, 11 Feb 2024 10:33:59 +0000 Subject: [PATCH] Add patch to make some player scavs hostile to player Refactored AIHelpers.BotIsPlayerScav to not require a BotOwner object --- project/Aki.Custom/AkiCustomPlugin.cs | 1 + project/Aki.Custom/CustomAI/AiHelpers.cs | 4 +- .../Patches/AddTraitorScavsPatch.cs | 64 +++++++++++++++++++ project/Aki.Custom/Patches/CustomAiPatch.cs | 5 +- 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 project/Aki.Custom/Patches/AddTraitorScavsPatch.cs diff --git a/project/Aki.Custom/AkiCustomPlugin.cs b/project/Aki.Custom/AkiCustomPlugin.cs index e3062ef..7fe005f 100644 --- a/project/Aki.Custom/AkiCustomPlugin.cs +++ b/project/Aki.Custom/AkiCustomPlugin.cs @@ -41,6 +41,7 @@ namespace Aki.Custom new AirdropFlarePatch().Enable(); new AddSptBotSettingsPatch().Enable(); new CustomAiPatch().Enable(); + new AddTraitorScavsPatch().Enable(); new ExitWhileLootingPatch().Enable(); new QTEPatch().Enable(); new PmcFirstAidPatch().Enable(); diff --git a/project/Aki.Custom/CustomAI/AiHelpers.cs b/project/Aki.Custom/CustomAI/AiHelpers.cs index 98484fe..53ff9c3 100644 --- a/project/Aki.Custom/CustomAI/AiHelpers.cs +++ b/project/Aki.Custom/CustomAI/AiHelpers.cs @@ -22,9 +22,9 @@ namespace Aki.Custom.CustomAI return (int)botRoleToCheck == AkiBotsPrePatcher.sptBearValue || (int)botRoleToCheck == AkiBotsPrePatcher.sptUsecValue; } - public static bool BotIsPlayerScav(WildSpawnType role, BotOwner ___botOwner_0) + public static bool BotIsPlayerScav(WildSpawnType role, string nickname) { - if (___botOwner_0.Profile.Info.Nickname.Contains("(") && role == WildSpawnType.assault) + if (role == WildSpawnType.assault && nickname.Contains("(")) { // Check bot is pscav by looking for the opening parentheses of their nickname e.g. scavname (pmc name) return true; diff --git a/project/Aki.Custom/Patches/AddTraitorScavsPatch.cs b/project/Aki.Custom/Patches/AddTraitorScavsPatch.cs new file mode 100644 index 0000000..5c20774 --- /dev/null +++ b/project/Aki.Custom/Patches/AddTraitorScavsPatch.cs @@ -0,0 +1,64 @@ +using Aki.Common.Http; +using Aki.Custom.Airdrops.Models; +using Aki.Custom.CustomAI; +using Aki.Reflection.Patching; +using Comfort.Common; +using EFT; +using HarmonyLib; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Aki.Custom.Patches +{ + public class AddTraitorScavsPatch : ModulePatch + { + private static int? TraitorChancePercent; + + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(BotSpawner), nameof(BotSpawner.GetGroupAndSetEnemies)); + } + + [PatchPrefix] + private static bool PatchPrefix(ref BotsGroup __result, IBotGame ____game, DeadBodiesController ____deadBodiesController, BotOwner bot, BotZone zone) + { + if (!TraitorChancePercent.HasValue) + { + string json = RequestHandler.GetJson("/singleplayer/scav/traitorscavhostile"); + TraitorChancePercent = JsonConvert.DeserializeObject(json); + } + + WildSpawnType role = bot.Profile.Info.Settings.Role; + if (AiHelpers.BotIsPlayerScav(role, bot.Profile.Info.Nickname) && new Random().Next(1, 100) > TraitorChancePercent) + { + Logger.LogInfo($"Making {bot.name} ({bot.Profile.Nickname}) hostile to player"); + + // Create a new group for this scav itself to belong to + var player = Singleton.Instance.MainPlayer; + var enemies = new List(); + var players = new List() { player }; + var botsGroup = new BotsGroup(zone, ____game, bot, enemies, ____deadBodiesController, players, false); + + // Because we don't want to use the zone-specific group, we add the new group with no key. This is similar to free for all + Singleton.Instance.BotsController.BotSpawner.Groups.AddNoKey(botsGroup, zone); + botsGroup.AddEnemy(player, EBotEnemyCause.checkAddTODO); + + // Make it so the player can kill the scav without aggroing the rest of the scavs + bot.Loyalty.CanBeFreeKilled = true; + + // Traitors dont talk + bot.BotTalk.SetSilence(9999); + + // Return our new botgroup + __result = botsGroup; + + // Skip original + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/project/Aki.Custom/Patches/CustomAiPatch.cs b/project/Aki.Custom/Patches/CustomAiPatch.cs index 7da2201..d14ee6f 100644 --- a/project/Aki.Custom/Patches/CustomAiPatch.cs +++ b/project/Aki.Custom/Patches/CustomAiPatch.cs @@ -29,12 +29,13 @@ namespace Aki.Custom.Patches [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)) + if (AiHelpers.BotIsPlayerScav(__state, ___botOwner_0.Profile.Info.Nickname)) { ___botOwner_0.Profile.Info.Settings.Role = aIBrainSpawnWeightAdjustment.GetRandomisedPlayerScavType(___botOwner_0, currentMapName); @@ -101,7 +102,7 @@ namespace Aki.Custom.Patches // Set spt bot bot back to original type ___botOwner_0.Profile.Info.Settings.Role = __state; } - else if (AiHelpers.BotIsPlayerScav(__state, ___botOwner_0)) + else if (AiHelpers.BotIsPlayerScav(__state, ___botOwner_0.Profile.Info.Nickname)) { // Set pscav back to original type ___botOwner_0.Profile.Info.Settings.Role = __state;