using System; 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.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("TheMassBinding")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("TheMassBinding")] [assembly: AssemblyTitle("TheMassBinding")] [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 TheMassMod { [BepInPlugin("com.vilcan.themassbinding", "The Mass Binding", "1.0")] public class TheMassPlugin : BaseUnityPlugin { public const string PluginGuid = "com.vilcan.themassbinding"; public const string PluginName = "The Mass Binding"; public const string PluginVersion = "1.0"; public static ConfigEntry HungerDecayMultiplier; public static ConfigEntry NerfedFoodFraction; public static ConfigEntry DenizenEatRestoreMultiplier; public static ConfigEntry DenizenMeatEatMultiplier; public static ConfigEntry StartingThreshold; public static ConfigEntry ThresholdStep; public static ConfigEntry StartingMeatCount; public static ConfigEntry SyncForeignHungerModules; public static ConfigEntry EatKey; public static ConfigEntry FoodMakerKey; public static ConfigEntry EatRange; public static ConfigEntry VerboseLogging; internal static ManualLogSource Logger; private Harmony _harmony; private void Awake() { //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; HungerDecayMultiplier = ((BaseUnityPlugin)this).Config.Bind("Hunger", "HungerDecayMultiplier", 1f, "Multiplier on the hunger decay rate. 1.0 = same pace as vanilla Survival Mode."); NerfedFoodFraction = ((BaseUnityPlugin)this).Config.Bind("Hunger", "NerfedFoodFraction", 0.1f, "Fraction of normal food's hunger restore that still applies while The Mass is active."); DenizenEatRestoreMultiplier = ((BaseUnityPlugin)this).Config.Bind("Hunger", "DenizenEatRestoreMultiplier", 1f, "Hunger restored by eating a denizen directly, as a multiple of a normal meal."); DenizenMeatEatMultiplier = ((BaseUnityPlugin)this).Config.Bind("Hunger", "DenizenMeatEatMultiplier", 1f, "Hunger restored by eating Denizen Meat, as a multiple of a normal meal."); StartingThreshold = ((BaseUnityPlugin)this).Config.Bind("Perks", "StartingThreshold", 5, "Denizens eaten needed for the first random perk."); ThresholdStep = ((BaseUnityPlugin)this).Config.Bind("Perks", "ThresholdStep", 5, "How much the required count increases after each perk reward."); StartingMeatCount = ((BaseUnityPlugin)this).Config.Bind("Hunger", "StartingMeatCount", 3, "Denizen Meat granted on taking the binding, in case you can't find a denizen right away."); SyncForeignHungerModules = ((BaseUnityPlugin)this).Config.Bind("Perks", "SyncForeignHungerModules", true, "When a granted perk brings its own hunger module (e.g. Conditioned Polyphagia), tune that module's stats to match The Mass's own and feed it from the denizen/Denizen Meat mechanic, instead of leaving it as a separate, unrelated hunger system. The perk keeps its own module and UI — only its numbers and restores are kept in sync. Disable to leave foreign hunger modules completely untouched."); EatKey = ((BaseUnityPlugin)this).Config.Bind("Controls", "EatKey", (KeyCode)103, "Hold both grab buttons on a denizen and press this to eat it."); FoodMakerKey = ((BaseUnityPlugin)this).Config.Bind("Controls", "FoodMakerKey", (KeyCode)120, "Hold both grab buttons on a denizen and press this to turn it into Denizen Meat instead."); EatRange = ((BaseUnityPlugin)this).Config.Bind("Controls", "EatRange", 3f, "Max distance to a denizen for the eat prompt to register."); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind("Debug", "VerboseLogging", false, "Per-frame eat-detection logging. Only useful for troubleshooting."); _harmony = new Harmony("com.vilcan.themassbinding"); _harmony.PatchAll(); Logger.LogInfo((object)"The Mass Binding loaded."); } } [HarmonyPatch(typeof(UI_TrinketPicker), "PopulateTrinkets")] public static class UI_TrinketPicker_PopulateTrinkets_Patch { [HarmonyPrefix] public static void Prefix(List trinketsToPopulate, Transform root, bool allowInIronKnuckle) { if (trinketsToPopulate != null && trinketsToPopulate.Count != 0 && trinketsToPopulate.Any((Trinket t) => (Object)(object)t != (Object)null && t.isBinding)) { TheMassBinding.EnsureRegistered(trinketsToPopulate); } } } [HarmonyPatch(typeof(HandItem_Food), "Eat")] public static class HandItem_Food_Eat_Patch { [HarmonyPostfix] public static void Postfix(HandItem_Food __instance) { if (((HandItem)(__instance?)).item != null && !(((HandItem)__instance).item.itemName != "Denizen Meat")) { PerkModule_TheMassEater.ActiveInstance?.OnDenizenMeatEaten(); } } } [HarmonyPatch(typeof(HandItem_Buff), "StartBuff")] public static class HandItem_Buff_StartBuff_Patch { [HarmonyPostfix] public static void Postfix(HandItem_Buff __instance) { if (((HandItem)(__instance?)).item != null && !(((HandItem)__instance).item.itemName != "Denizen Meat")) { PerkModule_TheMassEater.ActiveInstance?.OnDenizenMeatEaten(); } } } [HarmonyPatch(typeof(ENT_Player), "AddPerk")] public static class ENT_Player_AddPerk_Patch { [HarmonyPostfix] public static void Postfix(ENT_Player __instance, Perk perk, int stackAmount, bool firstTime, Perk __result) { if ((Object)(object)__instance == (Object)null || __result?.modules == null || __result.id == "Binding_TheMass" || !__instance.HasPerk("Binding_TheMass") || !TheMassPlugin.SyncForeignHungerModules.Value) { return; } PerkModule_TheMassEater activeInstance = PerkModule_TheMassEater.ActiveInstance; if (activeInstance == null) { return; } foreach (PerkModule_HungerMeter item in __result.modules.OfType()) { activeInstance.SyncForeignHungerModule(item); } } } public static class TheMassBinding { public const string BindingId = "Binding_TheMass"; private const string TrinketTitle = "The Mass"; public const string DenizenMeatItemName = "Denizen Meat"; private const string FunctionalItemPrefabName = "item_food_meat"; private const string CosmeticItemPrefabName = "item_food_meat"; private static readonly Color MeatTintOverride = new Color(0.35f, 1f, 0.35f, -1f); private static readonly Dictionary _prefabCache = new Dictionary(); private const string GrubSacrificeStat = "grubs-used"; private const string GrubSacrificeFlag = "session_sacrificed_grub"; public static void EnsureRegistered(List bindings) { if (bindings == null || bindings.Any((Trinket t) => (Object)(object)t != (Object)null && t.title == "The Mass")) { return; } Trinket hungerTemplate = ((IEnumerable)bindings).FirstOrDefault((Func)((Trinket t) => t?.perksToGrant != null && t.perksToGrant.OfType().Any((Perk p) => p.modules != null && p.modules.OfType().Any()))); if ((Object)(object)hungerTemplate == (Object)null) { TheMassPlugin.Logger.LogError((object)"[TheMassBinding] No hunger-based binding found to use as a template."); return; } Trinket val = ((IEnumerable)bindings).FirstOrDefault((Func)((Trinket t) => (Object)(object)t != (Object)null && !string.IsNullOrEmpty(t.title) && t.title.IndexOf("Hunted", StringComparison.OrdinalIgnoreCase) >= 0)) ?? ((IEnumerable)bindings).FirstOrDefault((Func)((Trinket t) => (Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)hungerTemplate)) ?? hungerTemplate; PerkModule_HungerMeter templateHunger = hungerTemplate.perksToGrant.First((Perk p) => p.modules.OfType().Any()).modules.OfType().First(); int activateOrder = ((bindings.Count != 0) ? bindings.Max((Trinket t) => t?.activateOrder ?? 0) : 0) + 1; Perk perk = BuildPerk(templateHunger, val); Trinket val2 = BuildTrinket(val, perk, activateOrder); bindings.Add(val2); RegisterInAssetDatabases(perk, val2); } private static void RegisterInAssetDatabases(Perk perk, Trinket trinket) { if (CL_AssetManager.instance == null || !(AccessTools.Field(typeof(CL_AssetManager), "databases").GetValue(CL_AssetManager.instance) is List list)) { return; } foreach (WKDatabaseHolder item in list) { if (!((Object)(object)item?.database == (Object)null)) { if (item.database.trinketAssets != null && !item.database.trinketAssets.Any((Trinket t) => (Object)(object)t != (Object)null && ((Object)t).name == ((Object)trinket).name)) { item.database.trinketAssets.Add(trinket); } if (item.database.perkAssets != null && !item.database.perkAssets.Any((Perk p) => (Object)(object)p != (Object)null && ((Object)p).name == ((Object)perk).name)) { item.database.perkAssets.Add(perk); } } } } private static Color ApplyMeatTint(Color original) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) float num = ((MeatTintOverride.a >= 0f) ? MeatTintOverride.a : original.a); return new Color(MeatTintOverride.r, MeatTintOverride.g, MeatTintOverride.b, num); } private static GameObject FindItemPrefabTemplate(string prefabName) { if (_prefabCache.TryGetValue(prefabName, out var value) && (Object)(object)value != (Object)null) { return value; } GameObject val = CL_AssetManager.GetFullCombinedAssetDatabase()?.itemPrefabs?.FirstOrDefault((Func)((GameObject p) => (Object)(object)p != (Object)null && ((Object)p).name.Equals(prefabName, StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val == (Object)null) { TheMassPlugin.Logger.LogWarning((object)("[TheMassBinding] '" + prefabName + "' not found in item prefab database.")); return null; } _prefabCache[prefabName] = val; return val; } public static void SpawnDenizenMeat(Vector3 position, ENT_Player player) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) GameObject obj = FindItemPrefabTemplate("item_food_meat"); Item_Object val = ((obj != null) ? obj.GetComponent() : null); if (val?.itemData == null) { TheMassPlugin.Logger.LogError((object)"[TheMassBinding] Can't create Denizen Meat — template item not found."); return; } Item clone = val.itemData.GetClone((Item)null, false); if (clone == null) { return; } clone.itemName = "Denizen Meat"; ApplyMeatCosmetics(clone); if (!((Object)(object)player == (Object)null)) { object? value = AccessTools.Field(typeof(ENT_Player), "inventory").GetValue(player); Inventory val2 = (Inventory)((value is Inventory) ? value : null); if ((Object)(object)val2 == (Object)null) { TheMassPlugin.Logger.LogError((object)"[TheMassBinding] Couldn't reach the player's inventory."); } else { val2.AddItemToInventoryScreen(position, clone, true, false, false); } } } public static void ApplyGrubSacrificeEquivalent() { try { Type type = AccessTools.TypeByName("StatManager"); object obj = AccessTools.Field(type, "sessionStats")?.GetValue(null); Type type2 = AccessTools.Inner(type, "GameStats"); if (obj != null && type2 != null) { AccessTools.Method(type2, "UpdateStatistic", new Type[6] { typeof(string), typeof(object), typeof(bool), typeof(bool), typeof(bool), typeof(bool) }, (Type[])null)?.Invoke(obj, new object[6] { "grubs-used", 1, false, true, false, true }); } AccessTools.Method(AccessTools.TypeByName("CL_GameManager"), "SetGameFlag", new Type[5] { typeof(string), typeof(bool), typeof(string), typeof(bool), typeof(bool) }, (Type[])null)?.Invoke(null, new object[5] { "session_sacrificed_grub", true, "", false, false }); } catch (Exception arg) { TheMassPlugin.Logger.LogError((object)$"[TheMassBinding] ApplyGrubSacrificeEquivalent failed: {arg}"); } } private static void ApplyMeatCosmetics(Item clone) { //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindItemPrefabTemplate("item_food_meat"); if ((Object)(object)val == (Object)null) { return; } Item val2 = val.GetComponent()?.itemData; if (val2 != null) { if ((Object)(object)val2.normalSprite != (Object)null) { clone.normalSprite = val2.normalSprite; } List pickupSounds = val2.pickupSounds; if (pickupSounds != null && pickupSounds.Count > 0) { clone.pickupSounds = new List(val2.pickupSounds); } } Transform obj = FindChildByName(val.transform, "Item_Food_Fruit"); Renderer val3 = ((obj != null) ? ((Component)obj).GetComponent() : null); MeshFilter val4 = ((obj != null) ? ((Component)obj).GetComponent() : null); SpriteRenderer val5 = null; HandItem_Buff val6 = null; if ((Object)(object)val2?.handItemAsset != (Object)null) { HandItem handItemAsset = val2.handItemAsset; val6 = (HandItem_Buff)(object)((handItemAsset is HandItem_Buff) ? handItemAsset : null); Transform obj2 = FindChildByName(((Component)val2.handItemAsset).transform, "ItemHands Item"); val5 = ((obj2 != null) ? ((Component)obj2).GetComponent() : null); } if ((Object)(object)clone.itemAsset != (Object)null && ((Object)(object)val3 != (Object)null || (Object)(object)val4 != (Object)null)) { GameObject obj3 = Object.Instantiate(((Component)clone.itemAsset).gameObject); ((Object)obj3).name = "DenizenMeat_ItemAsset(Clone)"; obj3.SetActive(false); Object.DontDestroyOnLoad((Object)(object)obj3); Renderer componentInChildren = obj3.GetComponentInChildren(true); MeshFilter componentInChildren2 = obj3.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)val3 != (Object)null) { componentInChildren.sharedMaterials = val3.sharedMaterials; Material material = componentInChildren.material; material.color = ApplyMeatTint(material.color); } if ((Object)(object)componentInChildren2 != (Object)null && (Object)(object)val4 != (Object)null) { componentInChildren2.sharedMesh = val4.sharedMesh; } Item_Object componentInChildren3 = obj3.GetComponentInChildren(true); if ((Object)(object)componentInChildren3 != (Object)null) { clone.itemAsset = componentInChildren3; } } if (!((Object)(object)clone.handItemAsset != (Object)null)) { return; } GameObject val7 = Object.Instantiate(((Component)clone.handItemAsset).gameObject); ((Object)val7).name = "DenizenMeat_HandItemAsset(Clone)"; val7.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val7); if ((Object)(object)val5 != (Object)null) { Transform obj4 = FindChildByName(val7.transform, "ItemHands Item"); SpriteRenderer val8 = ((obj4 != null) ? ((Component)obj4).GetComponent() : null); if ((Object)(object)val8 != (Object)null) { val8.sprite = val5.sprite; val8.color = ApplyMeatTint(val5.color); } } HandItem_Buff component = val7.GetComponent(); if ((Object)(object)component != (Object)null) { if ((Object)(object)val6 != (Object)null) { component.audioClip = val6.audioClip; component.audioVolume = val6.audioVolume; } component.buff = null; component.useSecondaryBuffs = false; component.secondaryBuffs = null; } HandItem componentInChildren4 = val7.GetComponentInChildren(true); if ((Object)(object)componentInChildren4 != (Object)null) { clone.handItemAsset = componentInChildren4; } } private static Transform FindChildByName(Transform root, string name) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown if ((Object)(object)root == (Object)null) { return null; } if (((Object)root).name == name) { return root; } foreach (Transform item in root) { Transform val = FindChildByName(item, name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Perk BuildPerk(PerkModule_HungerMeter templateHunger, Trinket cosmeticsTemplate) { //IL_003d: 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) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown Perk val = ScriptableObject.CreateInstance(); ((Object)val).name = "The Mass"; val.id = "Binding_TheMass"; val.title = "The Mass"; val.flavorText = "It bonds flesh. So do you, now."; val.description = $"Food barely sustains you. Grab & eat denizens ({TheMassPlugin.EatKey.Value}) instead."; val.perkType = (PerkType)9; val.spawnPool = (PerkPool)2; val.canStack = false; Perk val2 = cosmeticsTemplate?.perksToGrant?.FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { val.icon = val2.icon; val.iconMat = val2.iconMat; val.perkCard = val2.perkCard; val.perkFrame = val2.perkFrame; } float eatRecovery = templateHunger.eatRecovery; PerkModule_HungerMeter item = new PerkModule_HungerMeter { hungerMax = templateHunger.hungerMax, hungerMeter = templateHunger.hungerMax, hungerDecayRate = templateHunger.hungerDecayRate * TheMassPlugin.HungerDecayMultiplier.Value, eatRecovery = eatRecovery * TheMassPlugin.NerfedFoodFraction.Value, consumeBuffIDs = templateHunger.consumeBuffIDs, hungerMeterAsset = templateHunger.hungerMeterAsset, buff = CloneBuffContainer(templateHunger.buff), debuff = CloneBuffContainer(templateHunger.debuff), buffCurve = templateHunger.buffCurve, debuffCurve = templateHunger.debuffCurve, fullColor = templateHunger.fullColor, emptyColor = templateHunger.emptyColor, hungerTickAudio = templateHunger.hungerTickAudio }; val.modules = new List { (PerkModule)(object)item, (PerkModule)(object)new PerkModule_TheMassEater { NormalEatRecoveryAmount = eatRecovery } }; return val; } private static BuffContainer CloneBuffContainer(BuffContainer source) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0048: 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) //IL_0060: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown if (source == null) { return null; } return new BuffContainer { id = source.id + "_TheMassBinding", desc = source.desc, buffs = ((source.buffs != null) ? new List(source.buffs) : null), loseRate = source.loseRate, loseRateEffectedByPerks = source.loseRateEffectedByPerks, buffTime = source.buffTime, loseOverTime = source.loseOverTime, multiplier = source.multiplier }; } private static Trinket BuildTrinket(Trinket template, Perk perk, int activateOrder) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) Trinket obj = ScriptableObject.CreateInstance(); ((Object)obj).name = "The Mass"; obj.title = "The Mass"; obj.description = $"Food barely sustains you. Grab & eat denizens ({TheMassPlugin.EatKey.Value}) instead."; obj.flavorText = "It bonds flesh. So do you, now."; obj.isBinding = true; obj.icon = template.icon; obj.lockIcon = template.lockIcon; obj.cost = template.cost; obj.itemsToGrant = new List(); obj.perksToGrant = new List { perk }; obj.pouchesToGrant = 0; obj.scoreMultiplierBonus = template.scoreMultiplierBonus; obj.scoreBonus = template.scoreBonus; obj.comingSoon = false; obj.settingBlacklist = ((template.settingBlacklist != null) ? new List(template.settingBlacklist) : new List()); obj.activateOrder = activateOrder; return obj; } } [Serializable] public class PerkModule_TheMassEater : PerkModule { public float NormalEatRecoveryAmount = 25f; internal static PerkModule_TheMassEater ActiveInstance; private Perk _perkRef; private ENT_Player _player; private PerkModule_HungerMeter _hunger; private readonly List _syncedForeignHungerModules = new List(); private int _denizensEaten; private int _nextThreshold; private int _currentIncrement; private float _logTimer; private static readonly string[] NegativeTitleKeywords = new string[6] { "shattered", "fractured", "broken", "injury", "injured", "wound" }; public override void Initialize(Perk perk, bool isNew) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) ((PerkModule)this).Initialize(perk, isNew); _perkRef = perk; _hunger = perk.modules?.OfType().FirstOrDefault(); _player = Object.FindObjectOfType(); ActiveInstance = this; if (isNew) { _currentIncrement = TheMassPlugin.StartingThreshold.Value; _nextThreshold = _currentIncrement; if ((Object)(object)_player != (Object)null) { for (int i = 0; i < TheMassPlugin.StartingMeatCount.Value; i++) { TheMassBinding.SpawnDenizenMeat(((Component)_player).transform.position, _player); } } } if (!TheMassPlugin.SyncForeignHungerModules.Value || _player?.perks == null) { return; } foreach (Perk perk2 in _player.perks) { if ((Object)(object)perk2 == (Object)null || (Object)(object)perk2 == (Object)(object)perk || perk2.modules == null) { continue; } foreach (PerkModule_HungerMeter item in perk2.modules.OfType()) { SyncForeignHungerModule(item); } } } public override string GetCounterString() { return Mathf.Max(0, _nextThreshold - _denizensEaten).ToString(); } public void SyncForeignHungerModule(PerkModule_HungerMeter foreign) { if (_hunger != null && foreign != null && foreign != _hunger) { foreign.hungerMax = _hunger.hungerMax; foreign.hungerMeter = _hunger.hungerMeter; foreign.hungerDecayRate = _hunger.hungerDecayRate; foreign.eatRecovery = _hunger.eatRecovery; if (!_syncedForeignHungerModules.Contains(foreign)) { _syncedForeignHungerModules.Add(foreign); } if (TheMassPlugin.VerboseLogging.Value) { TheMassPlugin.Logger.LogInfo((object)("[TheMassBinding] Synced a foreign hunger module to match The Mass " + $"(hungerMax={foreign.hungerMax:F1}, decayRate={foreign.hungerDecayRate:F3}, " + $"eatRecovery={foreign.eatRecovery:F1}).")); } } } public override void Update() { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) ((PerkModule)this).Update(); if ((Object)(object)_player == (Object)null) { _player = Object.FindObjectOfType(); if ((Object)(object)_player == (Object)null) { return; } } bool mouseButton = Input.GetMouseButton(0); bool mouseButton2 = Input.GetMouseButton(1); bool flag = mouseButton && mouseButton2; Denizen val = null; string hitDebug = "not grabbing"; if (flag) { val = FindDenizenUnderCrosshair(out hitDebug); } if (TheMassPlugin.VerboseLogging.Value) { _logTimer += Time.deltaTime; if (_logTimer >= 1f) { _logTimer = 0f; TheMassPlugin.Logger.LogInfo((object)($"[TheMassBinding] LMB={mouseButton} RMB={mouseButton2} " + "target=" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "none") + " hits=[" + hitDebug + "] hunger=" + ((_hunger != null) ? _hunger.hungerMeter.ToString("F1") : "n/a"))); } } if (!flag || (Object)(object)val == (Object)null) { return; } if (Input.GetKeyDown(TheMassPlugin.EatKey.Value)) { try { EatDenizen(val); return; } catch (Exception arg) { TheMassPlugin.Logger.LogError((object)$"[TheMassBinding] EatDenizen failed: {arg}"); return; } } if (!Input.GetKeyDown(TheMassPlugin.FoodMakerKey.Value)) { return; } try { MakeFoodFromDenizen(val); } catch (Exception arg2) { TheMassPlugin.Logger.LogError((object)$"[TheMassBinding] MakeFoodFromDenizen failed: {arg2}"); } } private Denizen FindDenizenUnderCrosshair(out string hitDebug) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) hitDebug = ""; if ((Object)(object)_player.cam == (Object)null) { hitDebug = "no camera"; return null; } RaycastHit[] array = Physics.RaycastAll(new Ray(((Component)_player.cam).transform.position, ((Component)_player.cam).transform.forward), TheMassPlugin.EatRange.Value); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); List list = new List(); Denizen val = null; RaycastHit[] array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val2 = array2[num]; object obj = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent(); if (obj == null) { Rigidbody rigidbody = ((RaycastHit)(ref val2)).rigidbody; obj = ((rigidbody != null) ? ((Component)rigidbody).GetComponent() : null); if (obj == null) { Rigidbody rigidbody2 = ((RaycastHit)(ref val2)).rigidbody; obj = ((rigidbody2 != null) ? ((Component)rigidbody2).GetComponentInParent() : null); } } Denizen val3 = (Denizen)obj; bool flag = (Object)(object)val3 != (Object)null && IsBlacklisted(val3); list.Add(((Object)(object)val3 != (Object)null) ? (((Object)((Component)((RaycastHit)(ref val2)).collider).gameObject).name + "[Denizen" + (flag ? ",blacklisted" : "") + "]") : ((Object)((Component)((RaycastHit)(ref val2)).collider).gameObject).name); if ((Object)(object)val3 != (Object)null && !flag && (Object)(object)val == (Object)null) { val = val3; } } hitDebug = ((list.Count > 0) ? string.Join(", ", list) : "no hits"); return val; } private static bool IsBlacklisted(Denizen denizen) { return (Object)(object)((Component)denizen).GetComponent() != (Object)null; } private static bool IsGrub(Denizen denizen) { if ((Object)(object)denizen != (Object)null) { return (Object)(object)((Component)denizen).GetComponent() != (Object)null; } return false; } private void EatDenizen(Denizen denizen) { bool flag = IsGrub(denizen); if (KillAndRemoveDenizen(denizen)) { RestoreHunger(NormalEatRecoveryAmount * TheMassPlugin.DenizenEatRestoreMultiplier.Value); RegisterCredit(); if (flag) { TheMassBinding.ApplyGrubSacrificeEquivalent(); } } } private void MakeFoodFromDenizen(Denizen denizen) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) Vector3 position = ((Component)denizen).transform.position; bool flag = IsGrub(denizen); if (KillAndRemoveDenizen(denizen)) { if (flag) { TheMassBinding.ApplyGrubSacrificeEquivalent(); } TheMassBinding.SpawnDenizenMeat(position, _player); } } public void OnDenizenMeatEaten() { RestoreHunger(NormalEatRecoveryAmount * TheMassPlugin.DenizenMeatEatMultiplier.Value); } private bool KillAndRemoveDenizen(Denizen denizen) { if ((Object)(object)denizen == (Object)null || ((GameEntity)denizen).dead) { return false; } DamageInfo val = DamageInfo.CreateDamageInfo(9999f, (GameEntity)(object)_player, "Eaten"); ((GameEntity)denizen).Kill("Eaten", val); Object.Destroy((Object)(object)((Component)denizen).gameObject, 0.15f); return true; } private void RegisterCredit() { _denizensEaten++; if (_nextThreshold <= 0) { _currentIncrement = TheMassPlugin.StartingThreshold.Value; _nextThreshold = _currentIncrement; } if (_denizensEaten >= _nextThreshold) { GrantRandomPerk(); _currentIncrement += TheMassPlugin.ThresholdStep.Value; _nextThreshold += _currentIncrement; } } private void RestoreHunger(float amount) { if (_hunger == null) { _hunger = _perkRef?.modules?.OfType().FirstOrDefault(); } if (_hunger == null) { return; } _hunger.hungerMeter = Mathf.Clamp(_hunger.hungerMeter + amount, 0f, _hunger.hungerMax); for (int num = _syncedForeignHungerModules.Count - 1; num >= 0; num--) { PerkModule_HungerMeter val = _syncedForeignHungerModules[num]; if (val == null) { _syncedForeignHungerModules.RemoveAt(num); } else { val.hungerMeter = Mathf.Clamp(val.hungerMeter + amount, 0f, val.hungerMax); } } } private void GrantRandomPerk() { List list = (from p in Resources.FindObjectsOfTypeAll() where (Object)(object)p != (Object)null && p.id != "Binding_TheMass" && (int)p.perkType != 9 && (int)p.spawnPool != 2 && !IsNegativePerk(p) && !HasHungerModule(p) select p).ToList(); if (list.Count != 0) { _player.AddPerk(list[Random.Range(0, list.Count)], 1, true); } } private static bool HasHungerModule(Perk p) { if (p.modules != null) { return p.modules.OfType().Any(); } return false; } private static bool IsNegativePerk(Perk p) { if (!string.IsNullOrEmpty(p.id) && p.id.StartsWith("Injury", StringComparison.OrdinalIgnoreCase)) { return true; } if (!string.IsNullOrEmpty(p.title)) { string title = p.title.ToLowerInvariant(); if (NegativeTitleKeywords.Any((string k) => title.Contains(k))) { return true; } } return false; } } }