Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LostSurvivor v1.0.2
plugins/LostSurvivor.dll
Decompiled 21 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.CharacterAI; using RoR2.ExpansionManagement; using RoR2.Navigation; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LostSurvivor")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LostSurvivor")] [assembly: AssemblyTitle("LostSurvivor")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LostSurvivor { internal static class LostSurvivorConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<float> SpawnChance; public static ConfigEntry<int> MaxPerStage; public static ConfigEntry<float> SpawnDelay; public static ConfigEntry<float> MinDistanceFromPlayers; public static ConfigEntry<bool> AnnounceSpawn; public static ConfigEntry<string> SurvivorBlacklist; public static ConfigEntry<int> ItemsPerStage; public static ConfigEntry<bool> RandomizeItemCount; public static ConfigEntry<float> WhiteWeight; public static ConfigEntry<float> GreenWeight; public static ConfigEntry<float> RedWeight; public static ConfigEntry<float> BossWeight; public static ConfigEntry<bool> BankKillGold; public static ConfigEntry<int> CopiesPerStageCleared; public static ConfigEntry<bool> GiveMinionLeash; public static ConfigEntry<bool> AnnounceBefriend; private static string _blacklistSource; private static HashSet<string> _blacklist = new HashSet<string>(); public static HashSet<string> Blacklist { get { if (_blacklistSource != SurvivorBlacklist.Value) { _blacklistSource = SurvivorBlacklist.Value; _blacklist = new HashSet<string>(from s in (_blacklistSource ?? "").Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim() into s where s.Length > 0 select s, StringComparer.OrdinalIgnoreCase); } return _blacklist; } } public static void Init(ConfigFile cfg) { Enabled = cfg.Bind<bool>("1. General", "Enabled", true, "Master switch. When false, no Lost Survivors spawn. Survivors you have already befriended stay with you."); SpawnChance = cfg.Bind<float>("1. General", "Spawn Chance", 15f, "Percent chance (0-100) that a Lost Survivor appears when you enter a stage.\n0 = never, 100 = every stage. Rolled once per spawn slot (see Max Per Stage)."); MaxPerStage = cfg.Bind<int>("1. General", "Max Per Stage", 2, "How many times the spawn chance is rolled per stage, i.e. the most Lost Survivors that can appear on one stage.\nExample: 2 with a 50% chance -> 25% none, 50% one, 25% two."); SpawnDelay = cfg.Bind<float>("1. General", "Spawn Delay", 4f, "Seconds after the stage starts before the Lost Survivor is placed.\nA short delay lets players finish spawning so the distance check below works."); MinDistanceFromPlayers = cfg.Bind<float>("1. General", "Min Distance From Players", 60f, "The Lost Survivor spawns on a random ground node at least this many meters from every player,\nso you have to go find it. Falls back to any valid node if the map is too small."); AnnounceSpawn = cfg.Bind<bool>("1. General", "Announce Spawn", true, "Post a chat message when a Lost Survivor appears (it does NOT say where)."); SurvivorBlacklist = cfg.Bind<string>("1. General", "Survivor Blacklist", "", "Comma-separated BODY names that should never appear, e.g. \"MercBody, CaptainBody\".\nVanilla body names: CommandoBody, HuntressBody, Bandit2Body, ToolbotBody, EngiBody, MageBody, MercBody,\nTreebotBody, LoaderBody, CrocoBody, CaptainBody, RailgunnerBody, VoidSurvivorBody, SeekerBody,\nFalseSonBody, ChefBody. The exact names in YOUR game are printed to the BepInEx log at the start of each run\n(line \"Lost Survivor pool: ...\"). Modded survivors are included only if they ship an AI master."); ItemsPerStage = cfg.Bind<int>("2. Wild Items", "Items Per Stage", 4, "Item cap scales with the stage you are on: max items = Items Per Stage x current stage number.\nWith 4: stage 1 -> up to 4, stage 2 -> up to 8, stage 3 -> up to 12, and so on (loops keep counting)."); RandomizeItemCount = cfg.Bind<bool>("2. Wild Items", "Randomize Item Count", true, "true = the Lost Survivor gets a random amount from 1 up to the max above.\nfalse = it always gets exactly the max."); WhiteWeight = cfg.Bind<float>("2. Wild Items", "White Weight", 76f, "Relative odds that each rolled item is Common (white)."); GreenWeight = cfg.Bind<float>("2. Wild Items", "Green Weight", 16f, "Relative odds that each rolled item is Uncommon (green)."); RedWeight = cfg.Bind<float>("2. Wild Items", "Red Weight", 4f, "Relative odds that each rolled item is Legendary (red)."); BossWeight = cfg.Bind<float>("2. Wild Items", "Boss Weight", 4f, "Relative odds that each rolled item is Boss (yellow). 0 disables.\nWeights are relative: 76/16/4/4 means 76%, 16%, 4%, 4%. Items tagged AI Blacklist are always skipped."); BankKillGold = cfg.Bind<bool>("3. Companion", "Bank Kill Gold", true, "true = gold from enemies the wild Lost Survivor kills is held by it instead of going to players.\n Whoever befriends it receives the whole stash.\nfalse = its kills pay out to players normally and there is no stash."); CopiesPerStageCleared = cfg.Bind<int>("3. Companion", "Copies Per Stage Cleared", 3, "When a befriended survivor follows you into a new stage, it copies random items from your inventory.\nCopies gained = this value x stages completed. With 3: entering stage 3 (2 cleared) grants 6 copies.\nItems you hold more of are more likely to be picked. Set 0 to disable."); GiveMinionLeash = cfg.Bind<bool>("3. Companion", "Leash To Owner", true, "Gives befriended survivors the hidden drone leash, so they teleport back to you if they fall far behind."); AnnounceBefriend = cfg.Bind<bool>("3. Companion", "Announce Befriend", true, "Post a chat message when someone befriends a Lost Survivor, including how much gold it handed over."); } } internal class LostSurvivorInteractable : MonoBehaviour, IInteractable, IDisplayNameProvider { private CharacterBody body; private GameObject interactTrigger; public static void TryAttach(CharacterBody body) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 if (Object.op_Implicit((Object)(object)body) && !body.isPlayerControlled) { TeamIndex val = (TeamIndex)((!Object.op_Implicit((Object)(object)body.teamComponent)) ? (-1) : ((int)body.teamComponent.teamIndex)); if (((int)val == 1 || (int)val == -1) && (int)SurvivorCatalog.GetSurvivorIndexFromBodyIndex(body.bodyIndex) != -1 && (!NetworkServer.active || LostSurvivorTag.IsWild(body.master)) && !Object.op_Implicit((Object)(object)((Component)body).GetComponent<LostSurvivorInteractable>())) { ((Component)body).gameObject.AddComponent<LostSurvivorInteractable>(); } } } private void Awake() { body = ((Component)this).GetComponent<CharacterBody>(); } private void Start() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) interactTrigger = new GameObject("LostSurvivorInteractTrigger"); interactTrigger.layer = LayerIndex.pickups.intVal; interactTrigger.transform.SetParent(((Component)this).transform, false); interactTrigger.transform.localPosition = (Object.op_Implicit((Object)(object)body) ? ((Component)this).transform.InverseTransformPoint(body.corePosition) : Vector3.zero); SphereCollider obj = interactTrigger.AddComponent<SphereCollider>(); ((Collider)obj).isTrigger = true; obj.radius = Mathf.Max(2f, Object.op_Implicit((Object)(object)body) ? (body.bestFitRadius * 1.25f) : 2f); interactTrigger.AddComponent<EntityLocator>().entity = ((Component)this).gameObject; } private void FixedUpdate() { CharacterMaster val = (Object.op_Implicit((Object)(object)body) ? body.master : null); if (Object.op_Implicit((Object)(object)val) && (Object.op_Implicit((Object)(object)val.playerCharacterMasterController) || (Object.op_Implicit((Object)(object)val.minionOwnership) && Object.op_Implicit((Object)(object)val.minionOwnership.ownerMaster)))) { Object.Destroy((Object)(object)this); } } private void OnDestroy() { if (Object.op_Implicit((Object)(object)interactTrigger)) { Object.Destroy((Object)(object)interactTrigger); } } private bool IsWild() { if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.healthComponent) || !body.healthComponent.alive) { return false; } CharacterMaster master = body.master; if (!Object.op_Implicit((Object)(object)master)) { return false; } if (NetworkServer.active) { return LostSurvivorTag.IsWild(master); } if (!Object.op_Implicit((Object)(object)master.playerCharacterMasterController) && Object.op_Implicit((Object)(object)master.minionOwnership)) { return !Object.op_Implicit((Object)(object)master.minionOwnership.ownerMaster); } return false; } public string GetContextString(Interactor activator) { uint num = ((Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.master)) ? body.master.money : 0u); string text = (Object.op_Implicit((Object)(object)body) ? body.GetDisplayName() : "Survivor"); if (num == 0) { return "Befriend " + text; } return $"Befriend {text} <color=#FFE880>(${num})</color>"; } public Interactability GetInteractability(Interactor activator) { if (IsWild()) { CharacterBody val = (Object.op_Implicit((Object)(object)activator) ? ((Component)activator).GetComponent<CharacterBody>() : null); if (Object.op_Implicit((Object)(object)val) && val.isPlayerControlled) { return (Interactability)2; } return (Interactability)0; } return (Interactability)0; } public void OnInteractionBegin(Interactor activator) { LostSurvivorPlugin.Befriend(body, activator); } public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator) { return false; } public bool ShouldShowOnScanner() { return false; } public bool ShouldProximityHighlight() { return false; } public int GetInteractablePriority(Interactor activator) { return 0; } public bool ShouldSpawnLesserInteractionRewards(Interactor interactor) { return false; } public string GetDisplayName() { if (!Object.op_Implicit((Object)(object)body)) { return "Lost Survivor"; } return body.GetDisplayName(); } } internal class LostSurvivorPersistence : MonoBehaviour { private CharacterMaster master; private float nextCheck; private void Awake() { master = ((Component)this).GetComponent<CharacterMaster>(); } private void FixedUpdate() { if ((nextCheck -= Time.fixedDeltaTime) > 0f) { return; } nextCheck = 0.5f; if (!Object.op_Implicit((Object)(object)master)) { Object.Destroy((Object)(object)this); return; } CharacterMaster val = (Object.op_Implicit((Object)(object)master.minionOwnership) ? master.minionOwnership.ownerMaster : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.playerCharacterMasterController)) { return; } if (!Object.op_Implicit((Object)(object)((Component)this).GetComponent<MasterSuicideOnTimer>()) && (!Object.op_Implicit((Object)(object)master.inventory) || master.inventory.GetItemCountPermanent(Items.GummyCloneIdentifier) <= 0)) { if (!Util.IsDontDestroyOnLoad(((Component)this).gameObject)) { Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } if (NetworkServer.active && !Object.op_Implicit((Object)(object)((Component)this).GetComponent<LostSurvivorTag>())) { LostSurvivorTag lostSurvivorTag = ((Component)this).gameObject.AddComponent<LostSurvivorTag>(); lostSurvivorTag.befriended = true; lostSurvivorTag.lastCopyClearCount = (Object.op_Implicit((Object)(object)Run.instance) ? Run.instance.stageClearCount : 0); lostSurvivorTag.RequestRegroup(); if (LostSurvivorConfig.GiveMinionLeash.Value && Object.op_Implicit((Object)(object)master.inventory) && master.inventory.GetItemCountPermanent(Items.MinionLeash) == 0) { master.inventory.GiveItemPermanent(Items.MinionLeash, 1); } } } ((Behaviour)this).enabled = false; } } [BepInPlugin("com.lostsurvivor.LostSurvivor", "LostSurvivor", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class LostSurvivorPlugin : BaseUnityPlugin { public const string GUID = "com.lostsurvivor.LostSurvivor"; public const string NAME = "LostSurvivor"; public const string VERSION = "1.0.1"; private const string RiskOfOptionsGuid = "com.rune580.riskofoptions"; internal static ManualLogSource Log; internal static LostSurvivorPlugin Instance; private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; LostSurvivorConfig.Init(((BaseUnityPlugin)this).Config); if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { RiskOfOptionsCompat.Register(); } new Harmony("com.lostsurvivor.LostSurvivor").PatchAll(typeof(GoldBankPatch)); Stage.onServerStageBegin += OnServerStageBegin; CharacterBody.onBodyStartGlobal += LostSurvivorInteractable.TryAttach; RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(PrepareSurvivorMasterPrefabs)); Run.onRunStartGlobal += delegate { Log.LogInfo((object)("Lost Survivor pool: " + string.Join(", ", from s in SurvivorPool() select BodyCatalog.GetBodyName(BodyCatalog.FindBodyIndex(s.bodyPrefab))))); }; } private static void PrepareSurvivorMasterPrefabs() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (SurvivorDef allSurvivorDef in SurvivorCatalog.allSurvivorDefs) { if (!Object.op_Implicit((Object)(object)allSurvivorDef) || !Object.op_Implicit((Object)(object)allSurvivorDef.bodyPrefab)) { continue; } BodyIndex val = BodyCatalog.FindBodyIndex(allSurvivorDef.bodyPrefab); if ((int)val == -1) { continue; } MasterIndex val2 = MasterCatalog.FindAiMasterIndexForBody(val); if (!((MasterIndex)(ref val2)).isValid) { continue; } GameObject masterPrefab = MasterCatalog.GetMasterPrefab(val2); if (Object.op_Implicit((Object)(object)masterPrefab)) { if (!Object.op_Implicit((Object)(object)masterPrefab.GetComponent<AIOwnership>())) { masterPrefab.AddComponent<AIOwnership>(); } if (!Object.op_Implicit((Object)(object)masterPrefab.GetComponent<LostSurvivorPersistence>())) { masterPrefab.AddComponent<LostSurvivorPersistence>(); } num++; } } Log.LogInfo((object)$"Prepared {num} survivor AI masters."); } private void OnServerStageBegin(Stage stage) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 if (NetworkServer.active && Object.op_Implicit((Object)(object)Run.instance)) { LostSurvivorTag.GrantStageCopies(); if (LostSurvivorConfig.Enabled.Value && Object.op_Implicit((Object)(object)stage.sceneDef) && (int)stage.sceneDef.sceneType == 1) { ((MonoBehaviour)this).StartCoroutine(SpawnRoutine(stage)); } } } private IEnumerator SpawnRoutine(Stage stage) { yield return (object)new WaitForSeconds(Mathf.Max(0f, LostSurvivorConfig.SpawnDelay.Value)); if (!NetworkServer.active || (Object)(object)Stage.instance != (Object)(object)stage || !Object.op_Implicit((Object)(object)Run.instance)) { yield break; } for (int i = 0; i < Mathf.Max(0, LostSurvivorConfig.MaxPerStage.Value); i++) { if (Random.Range(0f, 100f) < LostSurvivorConfig.SpawnChance.Value) { TrySpawnLostSurvivor(); } } } internal static List<SurvivorDef> SurvivorPool() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) List<SurvivorDef> list = new List<SurvivorDef>(); foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs) { if (!Object.op_Implicit((Object)(object)orderedSurvivorDef) || orderedSurvivorDef.hidden || !Object.op_Implicit((Object)(object)orderedSurvivorDef.bodyPrefab)) { continue; } BodyIndex val = BodyCatalog.FindBodyIndex(orderedSurvivorDef.bodyPrefab); if ((int)val == -1 || LostSurvivorConfig.Blacklist.Contains(BodyCatalog.GetBodyName(val))) { continue; } ExpansionDef requiredExpansion = orderedSurvivorDef.GetRequiredExpansion(); if (!Object.op_Implicit((Object)(object)requiredExpansion) || !Object.op_Implicit((Object)(object)Run.instance) || Run.instance.IsExpansionEnabled(requiredExpansion)) { MasterIndex val2 = MasterCatalog.FindAiMasterIndexForBody(val); if (((MasterIndex)(ref val2)).isValid) { list.Add(orderedSurvivorDef); } } } return list; } private static void TrySpawnLostSurvivor() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown List<SurvivorDef> list = SurvivorPool(); if (list.Count == 0) { Log.LogWarning((object)"No eligible survivors to spawn."); return; } SurvivorDef val = list[Random.Range(0, list.Count)]; GameObject masterPrefab = MasterCatalog.GetMasterPrefab(MasterCatalog.FindAiMasterIndexForBody(BodyCatalog.FindBodyIndex(val.bodyPrefab))); if (!TryFindSpawnPosition(val.bodyPrefab.GetComponent<CharacterBody>().hullClassification, out var position)) { Log.LogWarning((object)("Couldn't find a spawn node for " + val.cachedName)); return; } CharacterMaster val2 = new MasterSummon { masterPrefab = masterPrefab, position = position, rotation = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f), teamIndexOverride = (TeamIndex)1, ignoreTeamMemberLimit = true, preSpawnSetupCallback = delegate(CharacterMaster m) { ((Component)m).gameObject.AddComponent<LostSurvivorTag>(); m.NetworkhideAllyCard = true; GiveWildItems(m.inventory); } }.Perform(); if (Object.op_Implicit((Object)(object)val2)) { Log.LogInfo((object)$"Spawned lost {val.cachedName} at {position} with {val2.inventory.GetTotalItemCount()} items."); if (LostSurvivorConfig.AnnounceSpawn.Value) { Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage { baseToken = "<color=#9FD8FF>A lost " + Language.GetString(val.displayNameToken) + " is wandering this stage...</color>" }); } } } private static bool TryFindSpawnPosition(HullClassification hull, out Vector3 position) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; NodeGraph val = (Object.op_Implicit((Object)(object)SceneInfo.instance) ? SceneInfo.instance.groundNodes : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } List<NodeIndex> activeNodesForHullMaskWithFlagConditions = val.GetActiveNodesForHullMaskWithFlagConditions((HullMask)(1 << (int)hull), (NodeFlags)0, (NodeFlags)4); if (activeNodesForHullMaskWithFlagConditions.Count == 0) { return false; } List<Vector3> source = (from val3 in PlayerCharacterMasterController.instances select (!Object.op_Implicit((Object)(object)val3.master)) ? null : val3.master.GetBodyObject() into b where Object.op_Implicit((Object)(object)b) select b.transform.position).ToList(); float minSqr = LostSurvivorConfig.MinDistanceFromPlayers.Value; minSqr *= minSqr; Vector3 p = default(Vector3); for (int num = 0; num < 64; num++) { NodeIndex val2 = activeNodesForHullMaskWithFlagConditions[Random.Range(0, activeNodesForHullMaskWithFlagConditions.Count)]; if (val.GetNodePosition(val2, ref p) && source.All(delegate(Vector3 pp) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Vector3 val3 = pp - p; return ((Vector3)(ref val3)).sqrMagnitude >= minSqr; })) { position = p; return true; } } return val.GetNodePosition(activeNodesForHullMaskWithFlagConditions[Random.Range(0, activeNodesForHullMaskWithFlagConditions.Count)], ref position); } private static void GiveWildItems(Inventory inv) { //IL_0180: Unknown result type (might be due to invalid IL or missing references) int num = Run.instance.stageClearCount + 1; int num2 = Mathf.Max(0, LostSurvivorConfig.ItemsPerStage.Value) * num; if (num2 <= 0) { return; } int num3 = (LostSurvivorConfig.RandomizeItemCount.Value ? Random.Range(1, num2 + 1) : num2); List<(List<ItemIndex>, float)> list = new List<(List<ItemIndex>, float)> { (Filter(Run.instance.availableTier1DropList), LostSurvivorConfig.WhiteWeight.Value), (Filter(Run.instance.availableTier2DropList), LostSurvivorConfig.GreenWeight.Value), (Filter(Run.instance.availableTier3DropList), LostSurvivorConfig.RedWeight.Value), (Filter(Run.instance.availableBossDropList), LostSurvivorConfig.BossWeight.Value) }.Where<(List<ItemIndex>, float)>(((List<ItemIndex> items, float weight) t) => t.items.Count > 0 && t.weight > 0f).ToList(); float num4 = list.Sum<(List<ItemIndex>, float)>(((List<ItemIndex> items, float weight) t) => t.weight); if (num4 <= 0f) { return; } for (int num5 = 0; num5 < num3; num5++) { float num6 = Random.Range(0f, num4); foreach (var (list2, num7) in list) { if (!((num6 -= num7) > 0f)) { inv.GiveItemPermanent(list2[Random.Range(0, list2.Count)], 1); break; } } } } private static List<ItemIndex> Filter(List<PickupIndex> pickups) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) List<ItemIndex> list = new List<ItemIndex>(); if (pickups == null) { return list; } foreach (PickupIndex pickup in pickups) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickup); if (pickupDef != null && (int)pickupDef.itemIndex != -1 && IsAiUsable(ItemCatalog.GetItemDef(pickupDef.itemIndex))) { list.Add(pickupDef.itemIndex); } } return list; } internal static bool IsAiUsable(ItemDef def) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 if (Object.op_Implicit((Object)(object)def) && !def.hidden && (int)def.tier != 5 && !def.ContainsTag((ItemTag)4) && !def.ContainsTag((ItemTag)13) && !def.ContainsTag((ItemTag)9)) { return !def.ContainsTag((ItemTag)10); } return false; } internal static void Befriend(CharacterBody body, Interactor activator) { //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown if (!NetworkServer.active || !Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.master)) { return; } CharacterMaster master = body.master; LostSurvivorTag component = ((Component)master).GetComponent<LostSurvivorTag>(); if (!Object.op_Implicit((Object)(object)component) || component.befriended) { return; } CharacterBody val = (Object.op_Implicit((Object)(object)activator) ? ((Component)activator).GetComponent<CharacterBody>() : null); CharacterMaster val2 = (Object.op_Implicit((Object)(object)val) ? val.master : null); if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.playerCharacterMasterController)) { component.befriended = true; master.NetworkhideAllyCard = false; component.lastCopyClearCount = Run.instance.stageClearCount; uint money = master.money; master.money = 0u; if (money != 0) { val2.GiveMoney(money); } master.minionOwnership.SetOwner(val2); Object.DontDestroyOnLoad((Object)(object)((Component)master).gameObject); BaseAI component2 = ((Component)master).GetComponent<BaseAI>(); (((Component)master).GetComponent<AIOwnership>() ?? ((Component)master).gameObject.AddComponent<AIOwnership>()).ownerMaster = val2; if (Object.op_Implicit((Object)(object)component2)) { component2.leader.gameObject = ((Component)val).gameObject; } if (LostSurvivorConfig.GiveMinionLeash.Value && master.inventory.GetItemCountPermanent(Items.MinionLeash) == 0) { master.inventory.GiveItemPermanent(Items.MinionLeash, 1); } if (LostSurvivorConfig.AnnounceBefriend.Value) { SimpleChatMessage val3 = new SimpleChatMessage(); val3.baseToken = "<color=#9FFFA8>" + Util.GetBestMasterName(val2) + " befriended the lost " + body.GetDisplayName() + ((money != 0) ? $" and received <color=#FFE880>${money}</color>!" : "!") + "</color>"; Chat.SendBroadcastChat((ChatMessageBase)(object)val3); } } } } internal class LostSurvivorTag : MonoBehaviour { public bool befriended; public int lastCopyClearCount; public bool needsRegroup; private float regroupTimeout; private static readonly List<LostSurvivorTag> all = new List<LostSurvivorTag>(); public void RequestRegroup() { needsRegroup = true; regroupTimeout = 30f; } private void FixedUpdate() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) if (!needsRegroup || !NetworkServer.active) { return; } if ((regroupTimeout -= Time.fixedDeltaTime) <= 0f) { needsRegroup = false; return; } CharacterMaster component = ((Component)this).GetComponent<CharacterMaster>(); CharacterBody val = (Object.op_Implicit((Object)(object)component) ? component.GetBody() : null); CharacterMaster val2 = ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.minionOwnership)) ? component.minionOwnership.ownerMaster : null); CharacterBody val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetBody() : null); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val3) && !Object.op_Implicit((Object)(object)val3.currentVehicle) && (!Object.op_Implicit((Object)(object)val3.characterMotor) || val3.characterMotor.isGrounded)) { Vector3 val4 = (Vector3)(((??)TeleportHelper.FindSafeTeleportDestination(val3.footPosition, val, new Xoroshiro128Plus((ulong)Random.Range(1, int.MaxValue)))) ?? val3.footPosition); TeleportHelper.TeleportBody(val, val4, false); needsRegroup = false; } } private void Awake() { all.Add(this); } private void OnDestroy() { all.Remove(this); } public static bool IsWild(CharacterMaster m) { if (!Object.op_Implicit((Object)(object)m)) { return false; } LostSurvivorTag component = ((Component)m).GetComponent<LostSurvivorTag>(); if (Object.op_Implicit((Object)(object)component)) { return !component.befriended; } return false; } public static void GrantStageCopies() { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) int stageClearCount = Run.instance.stageClearCount; int num = Mathf.Max(0, LostSurvivorConfig.CopiesPerStageCleared.Value); LostSurvivorTag[] array = all.ToArray(); foreach (LostSurvivorTag lostSurvivorTag in array) { if (!Object.op_Implicit((Object)(object)lostSurvivorTag) || !lostSurvivorTag.befriended || lostSurvivorTag.lastCopyClearCount >= stageClearCount) { continue; } lostSurvivorTag.lastCopyClearCount = stageClearCount; lostSurvivorTag.RequestRegroup(); CharacterMaster component = ((Component)lostSurvivorTag).GetComponent<CharacterMaster>(); CharacterMaster val = ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.minionOwnership)) ? component.minionOwnership.ownerMaster : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.inventory) || num == 0) { continue; } List<ItemIndex> list = new List<ItemIndex>(); foreach (ItemIndex item in val.inventory.itemAcquisitionOrder) { if (LostSurvivorPlugin.IsAiUsable(ItemCatalog.GetItemDef(item))) { int itemCountPermanent = val.inventory.GetItemCountPermanent(item); for (int j = 0; j < itemCountPermanent; j++) { list.Add(item); } } } if (list.Count != 0) { int num2 = num * stageClearCount; for (int k = 0; k < num2; k++) { component.inventory.GiveItemPermanent(list[Random.Range(0, list.Count)], 1); } LostSurvivorPlugin.Log.LogInfo((object)$"{((Object)component).name} copied {num2} items from {((Object)val).name}."); } } } } [HarmonyPatch(typeof(DeathRewards), "OnKilledServer")] internal static class GoldBankPatch { [HarmonyPrefix] private static void Prefix(DeathRewards __instance, DamageReport damageReport, out uint __state) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Invalid comparison between Unknown and I4 __state = 0u; if (!LostSurvivorConfig.BankKillGold.Value || damageReport == null) { return; } CharacterMaster val = null; if (LostSurvivorTag.IsWild(damageReport.attackerMaster)) { val = damageReport.attackerMaster; } else if (LostSurvivorTag.IsWild(damageReport.attackerOwnerMaster)) { val = damageReport.attackerOwnerMaster; } if (Object.op_Implicit((Object)(object)val)) { __state = __instance.goldReward; if (__state != 0) { uint num = (((int)Run.instance.selectedDifficulty >= 8) ? ((uint)((float)__state * 0.8f)) : __state); CharacterMaster obj = val; obj.money += num; __instance.goldReward = 0u; } } } [HarmonyPostfix] private static void Postfix(DeathRewards __instance, uint __state) { if (__state != 0) { __instance.goldReward = __state; } } } internal static class RiskOfOptionsCompat { [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void Register() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected O, but got Unknown //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Expected O, but got Unknown ModSettingsManager.SetModDescription("Sometimes a lost survivor is wandering the stage. Find it, press Interact to befriend it, and take the gold it collected."); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LostSurvivorConfig.Enabled)); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(LostSurvivorConfig.SpawnChance, new StepSliderConfig { min = 0f, max = 100f, increment = 1f, FormatString = "{0:0}%" })); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(LostSurvivorConfig.MaxPerStage, new IntSliderConfig { min = 1, max = 5 })); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(LostSurvivorConfig.SpawnDelay, new StepSliderConfig { min = 0f, max = 30f, increment = 0.5f, FormatString = "{0:0.0}s" })); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(LostSurvivorConfig.MinDistanceFromPlayers, new StepSliderConfig { min = 0f, max = 250f, increment = 5f, FormatString = "{0:0}m" })); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LostSurvivorConfig.AnnounceSpawn)); ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(LostSurvivorConfig.SurvivorBlacklist)); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(LostSurvivorConfig.ItemsPerStage, new IntSliderConfig { min = 0, max = 20 })); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LostSurvivorConfig.RandomizeItemCount)); StepSliderConfig val = new StepSliderConfig { min = 0f, max = 100f, increment = 1f, FormatString = "{0:0}" }; ModSettingsManager.AddOption((BaseOption)new StepSliderOption(LostSurvivorConfig.WhiteWeight, val)); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(LostSurvivorConfig.GreenWeight, val)); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(LostSurvivorConfig.RedWeight, val)); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(LostSurvivorConfig.BossWeight, val)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LostSurvivorConfig.BankKillGold)); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(LostSurvivorConfig.CopiesPerStageCleared, new IntSliderConfig { min = 0, max = 10 })); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LostSurvivorConfig.GiveMinionLeash)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LostSurvivorConfig.AnnounceBefriend)); } } }