using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading.Tasks; using BepInEx; using BepInEx.Logging; using GrubAdoption.Assets; using GrubAdoption.Rescuing; using GrubAdoption.Stats; using GrubAdoption.Utils; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; [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("com.anonymousfroggo.grubadoption")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.5.0")] [assembly: AssemblyInformationalVersion("0.2.5+5a0d0a84338f35dc2b896cf1bf4a589f73c05110")] [assembly: AssemblyProduct("Grub Adoption")] [assembly: AssemblyTitle("com.anonymousfroggo.grubadoption")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.5.0")] [module: UnverifiableCode] [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 GrubAdoption { [BepInPlugin("com.anonymousfroggo.grubadoption", "Grub Adoption", "0.2.5")] public class Plugin : BaseUnityPlugin { private string assemblyPath; private bool initialized; public static Plugin Instance { get; private set; } private void Awake() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Instance = this; new Harmony("com.anonymousfroggo.grubadoption").PatchAll(); SceneManager.sceneLoaded += OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) switch (((Scene)(ref scene)).name) { case "Intro": Initialize(); break; case "Game-Main": case "Playground": OnGameLoaded(scene); break; } } private async void Initialize() { if (!initialized) { Log.Initialize(((BaseUnityPlugin)this).Logger); assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); await GrubAdoptionAssets.Initialize(assemblyPath); initialized = true; } } private void OnGameLoaded(Scene scene) { } public static GameObject FindGameManagerGameObject(Scene scene) { GameObject val = (from gameObject in ((Scene)(ref scene)).GetRootGameObjects() where ((Object)gameObject).name == "GameManager" select gameObject).FirstOrDefault(); if ((Object)(object)val == (Object)null) { Log.Error("Finding GameManager failed"); return null; } return val; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.anonymousfroggo.grubadoption"; public const string PLUGIN_NAME = "Grub Adoption"; public const string PLUGIN_VERSION = "0.2.5"; } } namespace GrubAdoption.Utils { public static class AssetUtils { public const string BASE_DATABASE = "basedatabase"; public static GameObject GetAsset(string name) { return CL_AssetManager.GetAssetGameObject(name, "basedatabase"); } public static Item GetItem(string itemName) { return GetAsset(itemName).GetComponent().itemData; } } public class DebugHelper : MonoBehaviour { public static void Initialize(Scene scene) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Plugin.FindGameManagerGameObject(scene); if (obj != null) { obj.AddComponent(); } } private void Start() { CommandConsole.AddCommand("grubsstored", (Action)GrubsStoredCommand, true); CommandConsole.AddCommand("liststats", (Action)ListStatsCommand, true); CommandConsole.AddCommand("win", (Action)WinCommand, true); } private static void GrubsStoredCommand(string[] args) { CommandConsole.Log(GrubRescueStation.GetGrubsStored().ToString()); } private static void ListStatsCommand(string[] args) { StatUtils.StatSource result; if (args.Length == 0) { PrintStatsList(StatUtils.StatSource.global); PrintStatsList(StatUtils.StatSource.gamemode); PrintStatsList(StatUtils.StatSource.session); } else if (!Enum.TryParse(args[0], ignoreCase: true, out result)) { CommandConsole.LogError("Not a valid stat source: " + args[0]); } else { PrintStatsList(result); } static void PrintStatsList(StatUtils.StatSource source) { List list = new List(StatUtils.GetStats(source).statistics); list.Sort((Statistic x, Statistic y) => x.id.CompareTo(y.id)); foreach (Statistic item in list) { _ = item; } } } private static void WinCommand(string[] args) { CL_GameManager.gMan.Win(); } } public static class InventoryUtils { public static int TotalItemCount(string itemName) { return BagItemCount(itemName) + HandItemCount(itemName); } public static int BagItemCount(string itemName) { return ENT_Player.GetInventory().bagItems.Count((Item bagItem) => bagItem.itemName.Equals(itemName)); } public static int HandItemCount(string itemName) { return ENT_Player.GetInventory().itemHands.Count((ItemHand itemHand) => itemHand.currentItem != null && itemHand.currentItem.itemName.Equals(itemName)); } public static void LoadItemIntoBag(Item item) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) Item clone = item.GetClone((Item)null); clone.bagPosition = new Vector3(0f, 0f, 1f) + Random.insideUnitSphere * 0.01f; clone.bagRotation = Quaternion.LookRotation(clone.upDirection); Inventory.instance.AddItemToInventoryScreen(clone.bagPosition, clone, true, true, true); clone.inventory = Inventory.instance; } } public static class Log { private static ManualLogSource log; internal static void Initialize(ManualLogSource log) { Log.log = log; } public static void Info(object msg) { ManualLogSource obj = log; if (obj != null) { obj.LogInfo(msg); } } public static void Warn(object msg) { ManualLogSource obj = log; if (obj != null) { obj.LogWarning(msg); } } public static void Error(object msg) { ManualLogSource obj = log; if (obj != null) { obj.LogError(msg); } } public static void Debug(object msg) { ManualLogSource obj = log; if (obj != null) { obj.LogDebug(msg); } } } public static class Names { public static class Denizens { public const string GRUB = "Denizen_SlugGrub"; } public static class Gamemodes { public const string CAMPAIGN = "GM_Campaign"; public const string PLAYGROUND = "GM_Playground"; } public static class Items { public const string GRUB = "SlugGrub"; } public static class Scenes { public const string INTRO = "Intro"; public const string MAIN_MENU = "Main-Menu"; public const string GAME_MAIN = "Game-Main"; public const string PLAYGROUND = "Playground"; } public static class Stats { } public static class Ui { public const string SCORE_PANEL_STANDARD_PREFIX = "ScorePanel_Standard"; public const string SCORE_SCREEN_SESSION_STAT_PREFIX = "stat:"; public const string SCORE_SCREEN_GAMEMODE_STAT_PREFIX = "stat:"; public const string GAMEMODE_STAT_PREFIX = "stat-"; public const string LOGBOOK_STAT_PREFIX = "stat-"; } public const string GAME_MANAGER = "GameManager"; public static string Instantiated(string name) { return name + "(Clone)"; } } public static class Paths { } public static class StatUtils { public enum StatSource { session, gamemode, global } public const string STAT_PICKUP_ITEM_PREFIX = "pickup-item-"; public const string STAT_ITEMS_USED = "items-used"; public const string DEFAULT_TEXT_REDACTED = "[REDACTED]"; public static string GetText(CustomStat stat, StatSource statSource) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected I4, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) GameStats val = (GameStats)((int)statSource switch { 2 => StatManager.sessionStats, 0 => StatManager.saveData.GetGameMode(CL_GameManager.GetGamemodeName(true, false)).stats, 3 => StatManager.saveData.gameStats, _ => null, }); if (!val.HasStatistic(stat.GetId())) { return stat.GetDefaultText(statSource); } return stat.GetTextPrefix(statSource) + val.GetStatistic(stat.GetId()).GetString(); } public static bool HasStat(string id) { if (!StatManager.saveData.gameStats.HasStatistic(id)) { return StatManager.sessionStats.HasStatistic(id); } return true; } public static bool HasPickedUpItem(string itemName) { return HasStat("pickup-item-" + itemName); } public static object GetValueOrDefault(string id, object defaultValue, StatSource source) { Statistic stat = GetStat(id, source); return ((stat != null) ? stat.GetValue() : null) ?? defaultValue; } public static Statistic GetStat(string id, StatSource source) { GameStats stats = GetStats(source); if (stats == null) { return null; } return stats.GetStatistic(id); } public static GameStats GetStats(StatSource source) { return (GameStats)(source switch { StatSource.session => StatManager.sessionStats, StatSource.gamemode => StatManager.saveData.GetGameMode(CL_GameManager.GetGamemodeName(true, false))?.stats, StatSource.global => StatManager.saveData.gameStats, _ => null, }); } } public static class UiUtils { public static void Destroy(Transform child) { Object.Destroy((Object)(object)((Component)child).gameObject); } public static void DestroyChild(string childName, Transform parent) { Transform val = parent.Find(childName); if ((Object)(object)val == (Object)null) { Log.Error("Child " + childName + " of " + ((Object)parent).name + " not found"); } else { Destroy(val); } } } } namespace GrubAdoption.Stats { public abstract class CustomStat(string id, object initialValue, DataType dataType, ModType modType, DisplayType displayType, ModType globalModType) { private readonly string id = id; protected object value = initialValue; private readonly DataType type = dataType; private readonly ModType modType = modType; private readonly DisplayType displayType = displayType; private readonly ModType globalModType = globalModType; public void EndGameStatUpdate(bool win) { if (CalculateValueOnEndGame(win)) { WriteToSessionStats(); } } protected virtual bool CalculateValueOnEndGame(bool win) { return false; } private void WriteToSessionStats() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) StatManager.sessionStats.UpdateStatistic(id, initialValue, dataType, modType, displayType, globalModType); } public string GetId() { return id; } public abstract string GetDefaultText(StatSource statSource); public abstract string GetTextPrefix(StatSource statSource); public abstract bool ShouldAddToScoreScreenSession(bool win); public abstract bool ShouldAddToScoreScreenGamemode(bool win); public abstract bool ShouldAddToGamemode(M_Gamemode gamemode); public abstract bool ShouldAddToLogbook(); public virtual int GetScoreScreenSessionIndex() { return 0; } public virtual int GetScoreScreenGamemodeIndex() { return 0; } public virtual int GetGamemodeIndex() { return 0; } public virtual int GetLogbookIndex() { return 0; } } [HarmonyPatch] public class CustomStatManager { public enum StatSource { gamemode = 0, session = 2, global = 3 } private static readonly CustomStatManager instance = new CustomStatManager(); private readonly CustomStat[] customStats = new CustomStat[2] { new GrubsAdopted(), new MaxGrubsAdopted() }; public static bool Win { get; set; } [HarmonyPatch(typeof(CL_GameManager), "EndGameStatUpdate")] [HarmonyPostfix] public static void EndGameStatUpdate(bool win) { Win = win; CustomStat[] array = instance.customStats; for (int i = 0; i < array.Length; i++) { array[i].EndGameStatUpdate(Win); } GrubStats.UpdateGrubScore(); } [HarmonyPatch(typeof(UI_ScoreScreen), "ShowScreen")] [HarmonyPostfix] public static void AddStatsToScoreScreen(UI_ScoreScreen __instance) { if (!((Object)((Component)__instance).gameObject).name.StartsWith("ScorePanel_Standard")) { return; } Transform parent = ((Component)__instance).gameObject.transform.Find("Score Screen Root/Session Page/Board/Stats/SessionStats/Game Stats Simplified"); Transform parent2 = ((Component)__instance).gameObject.transform.Find("Score Screen Root/Session Page/Board/Stats/Best Stats/Top Score"); CustomStat[] array = instance.customStats; foreach (CustomStat customStat in array) { if (customStat.ShouldAddToScoreScreenSession(Win)) { Transform obj = InstantiateStatText(customStat, parent, "stat:", 4); obj.SetSiblingIndex(customStat.GetScoreScreenSessionIndex()); ((Component)((Component)obj).GetComponent()).GetComponent().text = StatUtils.GetText(customStat, (StatSource)2); } if (customStat.ShouldAddToScoreScreenGamemode(Win)) { Transform obj2 = InstantiateStatText(customStat, parent2, "stat:", 3); obj2.SetSiblingIndex(customStat.GetScoreScreenGamemodeIndex()); ((Component)((Component)obj2).GetComponent()).GetComponent().text = StatUtils.GetText(customStat, (StatSource)0); } } } [HarmonyPatch(typeof(UI_GamemodeScreen), "Initialize")] [HarmonyPostfix] public static void AddStatsToGamemode(UI_GamemodeScreen __instance, M_Gamemode mode) { Transform val = ((Component)__instance).gameObject.transform.Find("Gamemode_Panel_Base_Campaign(Clone)/Pages/Gamemode_Info_Screen/Mode Page/Board/Stats/Stats/Scoregrid-Extra"); if ((Object)(object)val == (Object)null) { return; } CustomStat[] array = instance.customStats; foreach (CustomStat customStat in array) { Transform val2 = val.Find("stat-" + customStat.GetId()); if ((Object)(object)val2 != (Object)null) { UiUtils.Destroy(val2); } if (customStat.ShouldAddToGamemode(mode)) { val2 = InstantiateStatText(customStat, val, "stat-", 1); val2.SetSiblingIndex(customStat.GetGamemodeIndex()); ((Component)val2).GetComponent().Refresh(); } } } [HarmonyPatch(typeof(UI_MenuScreen), "Initialize")] [HarmonyPostfix] public static void AddStatsToLogbook(UI_MenuScreen __instance) { if (!((Object)__instance).name.Equals("Logbook")) { return; } Transform parent = ((Component)__instance).gameObject.transform.Find("Stat Page/Board/Stats/Stats/Scoregrid-Extra"); UiUtils.DestroyChild("Break-Roaches.02", parent); UiUtils.DestroyChild("Break-Roaches", parent); CustomStat[] array = instance.customStats; foreach (CustomStat customStat in array) { if (customStat.ShouldAddToLogbook()) { Transform obj = InstantiateStatText(customStat, parent, "stat-", 1); obj.SetSiblingIndex(customStat.GetLogbookIndex()); ((Component)obj).GetComponent().Refresh(); } } } private static Transform InstantiateStatText(CustomStat stat, Transform parent, string uiNamePrefix, int instantiationIndex) { //IL_0033: 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) Transform transform = Object.Instantiate(((Component)parent.GetChild(instantiationIndex)).gameObject, parent).transform; ((Object)transform).name = uiNamePrefix + stat.GetId(); UT_StatText component = ((Component)transform).GetComponent(); component.defaultText = stat.GetDefaultText(component.source); component.textPrefix = stat.GetTextPrefix(component.source); ((Object)component).name = uiNamePrefix + stat.GetId(); component.statistic = stat.GetId(); return transform; } } public class GrubsAdopted : CustomStat { public const string ID = "grubs-adopted"; public const string DEFAULT_TEXT_NO_GRUBS = "Don't you care about Grubs? :("; public const string DEFAULT_TEXT_DEATH_WITH_GRUB = "You left your Grub alone T.T"; public const string DEFAULT_TEXT_DEATH_WITH_GRUBS = "You left your Grubs alone T.T"; public const string TEXT_PREFIX_SESSION = "Grubs Adopted: "; public const string TEXT_PREFIX_GLOBAL = "Total Grubs Adopted: "; public GrubsAdopted() : base("grubs-adopted", 0, (DataType)0, (ModType)1, (DisplayType)0, (ModType)1) { } protected override bool CalculateValueOnEndGame(bool win) { if (!win) { return false; } if (GrubStats.GetRescuedGrubsCount() == 0) { return false; } initialValue = GrubStats.GetRescuedGrubsCount(); return true; } public override string GetDefaultText(StatSource statSource) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!StatUtils.HasPickedUpItem("SlugGrub")) { return "[REDACTED]"; } if ((int)statSource == 2) { return (GrubRescueStation.GetGrubsStored() + InventoryUtils.TotalItemCount("SlugGrub")) switch { 0 => "Don't you care about Grubs? :(", 1 => "You left your Grub alone T.T", _ => "You left your Grubs alone T.T", }; } return GetTextPrefix(statSource) + 0; } public override string GetTextPrefix(StatSource statSource) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)statSource != 2) { return "Total Grubs Adopted: "; } return "Grubs Adopted: "; } public override bool ShouldAddToScoreScreenSession(bool win) { if (ShouldAddToGamemode(CL_GameManager.gamemode)) { return StatUtils.HasPickedUpItem("SlugGrub"); } return false; } public override bool ShouldAddToScoreScreenGamemode(bool win) { if (ShouldAddToGamemode(CL_GameManager.gamemode)) { return StatUtils.HasPickedUpItem("SlugGrub"); } return false; } public override bool ShouldAddToGamemode(M_Gamemode gamemode) { if (!((Object)gamemode).name.Equals("GM_Campaign")) { return ((Object)gamemode).name.Equals("GM_Playground"); } return true; } public override bool ShouldAddToLogbook() { return true; } public override int GetScoreScreenSessionIndex() { return 7; } public override int GetScoreScreenGamemodeIndex() { return 7; } public override int GetGamemodeIndex() { return 14; } public override int GetLogbookIndex() { return 13; } } public static class GrubStats { public const string ID_GRUB_SCORE = "grub-score"; public const string ID_GRUBS_ADOPTED = "grubs-adopted"; public const string ID_MAX_GRUBS_ADOPTED = "max-grubs-adopted"; public static float winScoreMultiplier = 5f; public static void UpdateGrubsAdopted() { } public static void UpdateGrubScore() { if (CL_GameManager.gMan.GetGameTime() != 0f) { float playerBestTravelDistance = CL_GameManager.gMan.GetPlayerBestTravelDistance(); int rescuedGrubsCount = GetRescuedGrubsCount(); float num = CL_GameManager.gMan.GetGameTime() / 60f; float num2 = playerBestTravelDistance * (float)rescuedGrubsCount / num; if (CustomStatManager.Win) { num2 *= winScoreMultiplier; } num2 = (float)Math.Round(num2, 2, MidpointRounding.AwayFromZero); Log.Info($"Grub Score: {num2}"); Log.Info($" = {(int)playerBestTravelDistance} Meters (Distance)" + $" * {rescuedGrubsCount} (#Grubs that made it out)" + $" / {(float)Math.Round(num, 2, MidpointRounding.AwayFromZero)} Minutes (Run Time)"); if (CustomStatManager.Win) { Log.Info(" * 5 (Because you escaped)"); } Statistic stat = StatUtils.GetStat("grub-score", StatUtils.StatSource.gamemode); string text = ((stat != null) ? stat.GetString() : null); Log.Info("Previous Best: " + (string.IsNullOrEmpty(text) ? "N/A" : text)); StatManager.sessionStats.UpdateStatistic("grub-score", (object)num2, (DataType)2, (ModType)0, (DisplayType)0, (ModType)2); } } public static int GetRescuedGrubsCount() { int num = GrubRescueStation.GetGrubsStored(); if (CustomStatManager.Win) { num += InventoryUtils.TotalItemCount("SlugGrub"); } return num; } } public class MaxGrubsAdopted : CustomStat { public MaxGrubsAdopted() : base("max-grubs-adopted", 0, (DataType)0, (ModType)2, (DisplayType)0, (ModType)2) { } protected override bool CalculateValueOnEndGame(bool win) { if (!win) { return false; } if (GrubStats.GetRescuedGrubsCount() == 0) { return false; } initialValue = GrubStats.GetRescuedGrubsCount(); return true; } public override string GetDefaultText(StatSource statSource) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!StatUtils.HasPickedUpItem("SlugGrub")) { return "[REDACTED]"; } return GetTextPrefix(statSource) + 0; } public override string GetTextPrefix(StatSource statSource) { return "Most Adopted in a Run: "; } public override bool ShouldAddToScoreScreenSession(bool win) { return false; } public override bool ShouldAddToScoreScreenGamemode(bool win) { if (ShouldAddToGamemode(CL_GameManager.gamemode)) { return StatUtils.HasPickedUpItem("SlugGrub"); } return false; } public override bool ShouldAddToGamemode(M_Gamemode gamemode) { if (!((Object)gamemode).name.Equals("GM_Campaign")) { return ((Object)gamemode).name.Equals("GM_Playground"); } return true; } public override bool ShouldAddToLogbook() { return true; } public override int GetScoreScreenGamemodeIndex() { return 8; } public override int GetGamemodeIndex() { return 15; } public override int GetLogbookIndex() { return 14; } } public class StatRequirement : MonoBehaviour { public enum OverrideMode { replace, and, or } public string id; public int fromInt = int.MinValue; public int toInt = int.MaxValue; public string matchString; public float fromFloat = float.NegativeInfinity; public float toFloat = float.PositiveInfinity; public StatUtils.StatSource source; public OverrideMode overrideMode; public bool metWhenUndefined; private void Start() { GameObject gameObject = ((Component)this).gameObject; gameObject.SetActive(overrideMode switch { OverrideMode.replace => IsMet(), OverrideMode.and => ((Component)this).gameObject.activeInHierarchy && IsMet(), OverrideMode.or => ((Component)this).gameObject.activeInHierarchy || IsMet(), _ => ((Component)this).gameObject.activeInHierarchy, }); } private bool IsMet() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected I4, but got Unknown Statistic stat = StatUtils.GetStat(id, source); if (stat == null) { return metWhenUndefined; } object value = stat.GetValue(); DataType type = stat.type; return (int)type switch { 0 => fromInt <= (int)value && (int)value <= toInt, 1 => (string)value == matchString, 2 => fromFloat <= (float)value && (float)value <= toFloat, _ => false, }; } } } namespace GrubAdoption.Rescuing { public class GrubDispenser : MonoBehaviour, Clickable { public float delayRangeDispenseGrub = 0.8f; private UT_AudioClipHandler clipHandler; private void Start() { clipHandler = ((Component)this).GetComponent(); } void Clickable.Interact(InteractionInfo info) { clipHandler.PlaySound("grub-dispensing:boop"); int grubsStored = GrubRescueStation.GetGrubsStored(); Log.Info($"Dispensing grubs: {grubsStored}"); Item grubItem; if (grubsStored != 0) { grubItem = AssetUtils.GetItem("Denizen_SlugGrub"); for (int i = 0; i < grubsStored; i++) { ((MonoBehaviour)this).StartCoroutine(AddGrubToBag()); } GrubRescueStation.ResetGrubsStored(); } IEnumerator AddGrubToBag() { yield return (object)new WaitForSeconds(Random.value * delayRangeDispenseGrub); InventoryUtils.LoadItemIntoBag(grubItem); clipHandler.PlaySound("grub-dispensing:dispense-grub"); } } bool Clickable.CanInteract(Interaction interaction) { return true; } public ObjectTagger GetTagger() { return ((Component)this).gameObject.GetComponent(); } public GameObject GetGameObject() { return ((Component)this).gameObject; } } public class GrubRescueStation : MonoBehaviour { public const string FLAG_GRUBS_STORED = "grubs-stored"; public float delayRangeExitInventory = 0.1f; public float delayEnterStation = 0.15f; private UT_AudioClipHandler clipHandler; private void Start() { clipHandler = ((Component)this).GetComponent(); } public void InsertGrub() { ((MonoBehaviour)this).StartCoroutine(PlaySounds()); SetGrubsStored(GetGrubsStored() + 1); Log.Info($"Grub inserted (stored: {GetGrubsStored()})"); IEnumerator PlaySounds() { if (clipHandler.GetGroup("grub-rescuing").GetSet("exit-inventory").aud.isPlaying) { yield return (object)new WaitForSeconds(delayRangeExitInventory); } clipHandler.PlaySound("grub-rescuing:exit-inventory"); yield return (object)new WaitForSeconds(delayEnterStation); clipHandler.PlaySound("grub-rescuing:enter-station"); } } public static int GetGrubsStored() { SessionFlag gameFlag = CL_GameManager.GetGameFlag("grubs-stored"); if (gameFlag == null || gameFlag.data == null) { return 0; } return int.Parse(gameFlag.data); } public static void ResetGrubsStored() { SetGrubsStored(0); } private static void SetGrubsStored(int amount) { CL_GameManager.SetGameFlag("grubs-stored", true, amount.ToString(), false, false); } } public class GrubSlot : MonoBehaviour, Clickable { private const string INTERACTOR_TAG = "GrubSlot"; private GrubRescueStation rescueStation; private void Start() { rescueStation = ((Component)this).GetComponentInParent(); if ((int)StatUtils.GetValueOrDefault("grubs-adopted", 0, StatUtils.StatSource.global) <= 0) { GetTagger().tags.Remove("GrubSlot"); } } void Clickable.Interact(InteractionInfo info) { rescueStation.InsertGrub(); } bool Clickable.CanInteract(Interaction interaction) { return interaction.curhand.inventoryHand.currentItem?.itemName == "SlugGrub"; } public ObjectTagger GetTagger() { return ((Component)this).gameObject.GetComponent(); } public GameObject GetGameObject() { return ((Component)this).gameObject; } } [HarmonyPatch] public static class GrubUsagePrevention { private static bool grubUsageDisabled = false; private static readonly Dictionary interactionClickables = new Dictionary { { 0, null }, { 1, null } }; [HarmonyPatch(typeof(HandItem_Buff), "Use")] [HarmonyPrefix] public static bool PreventGrubUse(HandItem_Buff __instance) { Clickable interactorClickable = GetInteractorClickable(((Hand_Base)__instance).hand.id); if (((HandItem)__instance).item.itemName != "SlugGrub") { return true; } if (grubUsageDisabled || interactorClickable is GrubSlot || interactorClickable is GrubDispenser) { return false; } return true; } [HarmonyPatch(typeof(Item_InteractionModule), "CanInteractWithInteractable")] [HarmonyPostfix] public static void SetInteractorClickables(Interaction interaction) { interactionClickables[interaction.curhand.id] = interaction.clickable; } [HarmonyPatch(typeof(Inventory), "Update")] [HarmonyPostfix] public static void ResetInteractorClickables() { interactionClickables[0] = null; interactionClickables[1] = null; } public static Clickable GetInteractorClickable(int handId) { if (!interactionClickables.ContainsKey(handId)) { return null; } return interactionClickables[handId]; } } } namespace GrubAdoption.Assets { [HarmonyPatch] public static class GrubAdoptionAssets { private static readonly string ASSET_BUNDLE_FILE = "grub-adoption.assets"; private static AssetBundle assetBundle; public static GameObject LevelModifications_Campaign { get; private set; } public static Sprite GrubInteractionSprite { get; private set; } public static Item_InteractionModule GrubInteractor { get; private set; } public static GameObject LevelModifications_Debug { get; private set; } public static async Task Initialize(string assemblyPath) { string assetBundlePath = Path.Combine(assemblyPath, ASSET_BUNDLE_FILE); AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(assetBundlePath); if (request == null) { Log.Error("Failed to load asset bundle: " + assetBundlePath); return; } while (!((AsyncOperation)request).isDone) { await Task.Yield(); } assetBundle = request.assetBundle; if (assetBundle == null) { Log.Error("Failed to load asset bundle: " + assetBundlePath); return; } Log.Info("Successfully loaded asset bundle"); InitializeLevelModifications(); InitializeGrubInteractor(); } private static void InitializeLevelModifications() { LevelModificationLoader levelModificationLoader = new LevelModificationLoader((M_Gamemode gamemode) => ((Object)gamemode).name == "GM_Campaign" && !gamemode.IsIronKnuckle()); LevelModifications_Campaign = assetBundle.LoadAsset("LevelModifications_Campaign"); if ((Object)(object)LevelModifications_Campaign == (Object)null) { LoadError("LevelModifications_Campaign"); } else { levelModificationLoader.RegisterModificationsFromChildren(LevelModifications_Campaign); } } private static void InitializeGrubInteractor() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) GrubInteractionSprite = assetBundle.LoadAsset("GrubInteractionSprite"); if ((Object)(object)GrubInteractionSprite == (Object)null) { LoadError("GrubInteractionSprite"); return; } GrubInteractor = new Item_InteractionModule(); GrubInteractor.interactorName = "Grub"; GrubInteractor.interactionTag = "GrubSlot"; GrubInteractor.interactionSprite = GrubInteractionSprite; GrubInteractor.interactionType = (InteractionType)1; } [HarmonyPatch(typeof(Item), "InitializeInHand")] [HarmonyPostfix] public static void TrySetInteractor(Item __instance) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (GrubInteractor == null) { LoadError("GrubInteractor"); } else { if (__instance.itemName != "SlugGrub") { return; } HandItem handItem = __instance.GetHandItem(); if (handItem.interactionModules != null && handItem.interactionModules.Contains(GrubInteractor)) { Log.Info("This Grub already has a GrubInteractor in its interactionModules"); return; } if (handItem.HasInteractor()) { handItem.interactionModules.Add(GrubInteractor); Log.Info("Added GrubInteractor to interactionModules"); } else { handItem.interactionModules = new List(1) { GrubInteractor }; Log.Info("Set interactionModules to [GrubInteractor]"); } __instance.interactType = (InteractType)2; } } private static void LoadError(string assetName) { Log.Error("Loading " + assetName + " failed"); } } public class LevelModification { private const string ASSET_PREFIX = "LM_"; private readonly GameObject asset; private readonly LevelModificationLoader loader; public string Level { get; } public LevelModification(GameObject asset, LevelModificationLoader loader) { this.asset = asset; this.loader = loader; string name = ((Object)asset).name; if (!name.StartsWith("LM_")) { Log.Error("Error while loading LevelModification " + name + ": Name must match pattern LM_"); } else { Level = name.Substring("LM_".Length); } } public void InjectInto(GameObject levelObject) { Log.Info("Injecting a LevelModification into " + Level); InjectRecursive(asset.transform, levelObject.transform); } private void InjectRecursive(Transform assetNode, Transform levelObjectNode) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in assetNode) { Transform val = item; Transform val2 = levelObjectNode.Find(((Object)val).name); if ((Object)(object)val2 != (Object)null) { InjectRecursive(val, val2); continue; } Log.Info("Injecting " + ((Object)val).name + " at " + ((Object)levelObjectNode).name); ((Object)Object.Instantiate(val, levelObjectNode)).name = loader.GetScopedName(((Object)val).name); } } } [HarmonyPatch] public class LevelModificationLoader { private static readonly List loaders = new List(); private readonly Func LoadInGamemode; private readonly Dictionary modificationsDict = new Dictionary(); public LevelModificationLoader(Func LoadInGamemode = null) { this.LoadInGamemode = LoadInGamemode ?? ((Func)((M_Gamemode _) => true)); loaders.Add(this); } public void RegisterModification(GameObject modificationAsset) { LevelModification levelModification = new LevelModification(modificationAsset, this); modificationsDict.Add(levelModification.Level, levelModification); Log.Info("Registered LevelModification for " + levelModification.Level); } public void RegisterModificationsFromChildren(GameObject parent) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown foreach (Transform item in parent.transform) { Transform val = item; RegisterModification(((Component)val).gameObject); } } public string GetScopedName(string name) { return name + " (com.anonymousfroggo.grubadoption)"; } [HarmonyPatch(typeof(M_Level), "Awake")] [HarmonyPostfix] public static void InjectLevelModifications(M_Level __instance) { foreach (LevelModificationLoader item in loaders.Where((LevelModificationLoader loader) => loader.LoadInGamemode(CL_GameManager.gamemode) && loader.modificationsDict.ContainsKey(__instance.levelName))) { item.modificationsDict[__instance.levelName].InjectInto(((Component)__instance).gameObject); } } } }