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<float> HungerDecayMultiplier;
public static ConfigEntry<float> NerfedFoodFraction;
public static ConfigEntry<float> DenizenEatRestoreMultiplier;
public static ConfigEntry<float> DenizenMeatEatMultiplier;
public static ConfigEntry<int> StartingThreshold;
public static ConfigEntry<int> ThresholdStep;
public static ConfigEntry<int> StartingMeatCount;
public static ConfigEntry<bool> SyncForeignHungerModules;
public static ConfigEntry<KeyCode> EatKey;
public static ConfigEntry<KeyCode> FoodMakerKey;
public static ConfigEntry<float> EatRange;
public static ConfigEntry<bool> 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<float>("Hunger", "HungerDecayMultiplier", 1f, "Multiplier on the hunger decay rate. 1.0 = same pace as vanilla Survival Mode.");
NerfedFoodFraction = ((BaseUnityPlugin)this).Config.Bind<float>("Hunger", "NerfedFoodFraction", 0.1f, "Fraction of normal food's hunger restore that still applies while The Mass is active.");
DenizenEatRestoreMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Hunger", "DenizenEatRestoreMultiplier", 1f, "Hunger restored by eating a denizen directly, as a multiple of a normal meal.");
DenizenMeatEatMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Hunger", "DenizenMeatEatMultiplier", 1f, "Hunger restored by eating Denizen Meat, as a multiple of a normal meal.");
StartingThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "StartingThreshold", 5, "Denizens eaten needed for the first random perk.");
ThresholdStep = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "ThresholdStep", 5, "How much the required count increases after each perk reward.");
StartingMeatCount = ((BaseUnityPlugin)this).Config.Bind<int>("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<bool>("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<KeyCode>("Controls", "EatKey", (KeyCode)103, "Hold both grab buttons on a denizen and press this to eat it.");
FoodMakerKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("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<float>("Controls", "EatRange", 3f, "Max distance to a denizen for the eat prompt to register.");
VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("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<Trinket> 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<PerkModule_HungerMeter>())
{
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<string, GameObject> _prefabCache = new Dictionary<string, GameObject>();
private const string GrubSacrificeStat = "grubs-used";
private const string GrubSacrificeFlag = "session_sacrificed_grub";
public static void EnsureRegistered(List<Trinket> bindings)
{
if (bindings == null || bindings.Any((Trinket t) => (Object)(object)t != (Object)null && t.title == "The Mass"))
{
return;
}
Trinket hungerTemplate = ((IEnumerable<Trinket>)bindings).FirstOrDefault((Func<Trinket, bool>)((Trinket t) => t?.perksToGrant != null && t.perksToGrant.OfType<Perk>().Any((Perk p) => p.modules != null && p.modules.OfType<PerkModule_HungerMeter>().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<Trinket>)bindings).FirstOrDefault((Func<Trinket, bool>)((Trinket t) => (Object)(object)t != (Object)null && !string.IsNullOrEmpty(t.title) && t.title.IndexOf("Hunted", StringComparison.OrdinalIgnoreCase) >= 0)) ?? ((IEnumerable<Trinket>)bindings).FirstOrDefault((Func<Trinket, bool>)((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<PerkModule_HungerMeter>().Any()).modules.OfType<PerkModule_HungerMeter>().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<WKDatabaseHolder> 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, bool>)((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<Item_Object>() : 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<Item_Object>()?.itemData;
if (val2 != null)
{
if ((Object)(object)val2.normalSprite != (Object)null)
{
clone.normalSprite = val2.normalSprite;
}
List<AudioClip> pickupSounds = val2.pickupSounds;
if (pickupSounds != null && pickupSounds.Count > 0)
{
clone.pickupSounds = new List<AudioClip>(val2.pickupSounds);
}
}
Transform obj = FindChildByName(val.transform, "Item_Food_Fruit");
Renderer val3 = ((obj != null) ? ((Component)obj).GetComponent<Renderer>() : null);
MeshFilter val4 = ((obj != null) ? ((Component)obj).GetComponent<MeshFilter>() : 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<SpriteRenderer>() : null);
}
if ((Object)(object)clone.itemAsset != (Object)null && ((Object)(object)val3 != (Object)null || (Object)(object)val4 != (Object)null))
{
GameObject obj3 = Object.Instantiate<GameObject>(((Component)clone.itemAsset).gameObject);
((Object)obj3).name = "DenizenMeat_ItemAsset(Clone)";
obj3.SetActive(false);
Object.DontDestroyOnLoad((Object)(object)obj3);
Renderer componentInChildren = obj3.GetComponentInChildren<Renderer>(true);
MeshFilter componentInChildren2 = obj3.GetComponentInChildren<MeshFilter>(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<Item_Object>(true);
if ((Object)(object)componentInChildren3 != (Object)null)
{
clone.itemAsset = componentInChildren3;
}
}
if (!((Object)(object)clone.handItemAsset != (Object)null))
{
return;
}
GameObject val7 = Object.Instantiate<GameObject>(((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<SpriteRenderer>() : null);
if ((Object)(object)val8 != (Object)null)
{
val8.sprite = val5.sprite;
val8.color = ApplyMeatTint(val5.color);
}
}
HandItem_Buff component = val7.GetComponent<HandItem_Buff>();
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<HandItem>(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<Perk>();
((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>
{
(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<Buff>(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<Trinket>();
((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<Item_Object>();
obj.perksToGrant = new List<Perk> { perk };
obj.pouchesToGrant = 0;
obj.scoreMultiplierBonus = template.scoreMultiplierBonus;
obj.scoreBonus = template.scoreBonus;
obj.comingSoon = false;
obj.settingBlacklist = ((template.settingBlacklist != null) ? new List<string>(template.settingBlacklist) : new List<string>());
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<PerkModule_HungerMeter> _syncedForeignHungerModules = new List<PerkModule_HungerMeter>();
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<PerkModule_HungerMeter>().FirstOrDefault();
_player = Object.FindObjectOfType<ENT_Player>();
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<PerkModule_HungerMeter>())
{
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<ENT_Player>();
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<string> list = new List<string>();
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<Denizen>();
if (obj == null)
{
Rigidbody rigidbody = ((RaycastHit)(ref val2)).rigidbody;
obj = ((rigidbody != null) ? ((Component)rigidbody).GetComponent<Denizen>() : null);
if (obj == null)
{
Rigidbody rigidbody2 = ((RaycastHit)(ref val2)).rigidbody;
obj = ((rigidbody2 != null) ? ((Component)rigidbody2).GetComponentInParent<Denizen>() : 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<DEN_Roach>() != (Object)null;
}
private static bool IsGrub(Denizen denizen)
{
if ((Object)(object)denizen != (Object)null)
{
return (Object)(object)((Component)denizen).GetComponent<DEN_SlugGrub>() != (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<PerkModule_HungerMeter>().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<Perk> list = (from p in Resources.FindObjectsOfTypeAll<Perk>()
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<PerkModule_HungerMeter>().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;
}
}
}