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 GameNetcodeStuff; using HarmonyLib; using LethalLib.Modules; using Microsoft.CodeAnalysis; using PillBottleMod.Items; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PillBottleMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("A consumable pill bottle shop item with a speed/stamina buff, hangover, withdrawal, and overdose mechanic.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("PillBottleMod")] [assembly: AssemblyTitle("PillBottleMod")] [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 PillBottleMod { public class PillBottleHud : MonoBehaviour { public static PillBottleHud Instance; private Texture2D _pixel; private GUIStyle _statusStyle; private GUIStyle _smallStyle; private bool _loggedFirstGui; private bool _loggedFirstDraw; public static void EnsureExists() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("PillBottleHud"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent(); } } private void Awake() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; _pixel = new Texture2D(1, 1); _pixel.SetPixel(0, 0, Color.white); _pixel.Apply(); Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[PillBottle] HUD initialised."); } } private static bool ShouldDraw() { if (!PillBottleEffectManager.LocalHasState) { return false; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } PlayerControllerB localPlayerController = instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null) { return false; } if (localPlayerController.isPlayerDead) { return false; } return true; } private void OnGUI() { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) if (!_loggedFirstGui) { _loggedFirstGui = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[PillBottle] HUD OnGUI is running."); } } if (!ShouldDraw()) { return; } if (!_loggedFirstDraw) { _loggedFirstDraw = true; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[PillBottle] HUD draw condition met (buff={PillBottleEffectManager.LocalBuffActive}, addiction={PillBottleEffectManager.LocalAddiction:0}%)."); } } Rect r = default(Rect); ((Rect)(ref r))..ctor(0f, 0f, (float)Screen.width, (float)Screen.height); if (PillBottleEffectManager.LocalBuffActive) { Fill(r, new Color(0.12f, 0.42f, 1f, 0.28f)); } else if (PillBottleEffectManager.LocalHangoverActive) { Fill(r, new Color(0.25f, 0.35f, 0.15f, 0.22f)); } float localAddiction = PillBottleEffectManager.LocalAddiction; if (localAddiction > 25f) { float num = Mathf.Lerp(0.05f, 0.35f, Mathf.InverseLerp(25f, 100f, localAddiction)); Fill(r, new Color(0.6f, 0f, 0f, num)); } DrawMeters(localAddiction); } private void DrawMeters(float addiction) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: 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) if (_statusStyle == null) { _statusStyle = new GUIStyle(GUI.skin.label) { fontSize = 16, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; _smallStyle = new GUIStyle(GUI.skin.label) { fontSize = 12, alignment = (TextAnchor)4 }; } float localOverdose = PillBottleEffectManager.LocalOverdose; bool flag = localOverdose > 0.001f; int num = ((!flag) ? 1 : 2); float num2 = 26f + (float)num * 36f + 8f; float num3 = ((float)Screen.width - 260f) * 0.5f; float num4 = (float)Screen.height - 40f - num2; Fill(new Rect(num3 - 10f, num4, 280f, num2), new Color(0f, 0f, 0f, 0.5f)); float num5 = num4 + 6f; string text = (PillBottleEffectManager.LocalBuffActive ? "BUFFED" : (PillBottleEffectManager.LocalHangoverActive ? "HANGOVER" : ((addiction > 0f) ? "WITHDRAWAL" : "CLEAN"))); if (PillBottleEffectManager.LocalStaminaActive) { text += " +STAMINA"; } GUI.color = Color.white; GUI.Label(new Rect(num3, num5, 260f, 20f), text, _statusStyle); num5 += 26f; Color fill = Color.Lerp(new Color(0.25f, 0.8f, 0.25f), new Color(0.9f, 0.12f, 0.12f), Mathf.Clamp01(addiction / 100f)); DrawLabeledBar(num3, num5, 260f, 16f, Mathf.Clamp01(addiction / 100f), fill, $"Addiction {addiction:0}%"); num5 += 36f; if (flag) { Color fill2 = Color.Lerp(new Color(1f, 0.6f, 0f), new Color(1f, 0.1f, 0.1f), localOverdose); DrawLabeledBar(num3, num5, 260f, 16f, localOverdose, fill2, $"Overdose {localOverdose * 100f:0}%"); } } private void DrawLabeledBar(float x, float y, float w, float h, float frac, Color fill, string label) { //IL_0007: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) Fill(new Rect(x, y, w, h), new Color(0.12f, 0.12f, 0.12f, 0.95f)); Fill(new Rect(x, y, w * Mathf.Clamp01(frac), h), fill); GUI.color = Color.white; GUI.Label(new Rect(x, y + h, w, 16f), label, _smallStyle); GUI.color = Color.white; } private void Fill(Rect r, Color c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = c; GUI.DrawTexture(r, (Texture)(object)_pixel); GUI.color = color; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("yourname.pillbottlemod", "Pill Bottle Mod", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string ModGUID = "yourname.pillbottlemod"; public const string ModName = "Pill Bottle Mod"; public const string ModVersion = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry PillBottlePrice; internal static ConfigEntry AddictionSecondsToMax; private readonly Harmony _harmony = new Harmony("yourname.pillbottlemod"); private void Awake() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Pill Bottle Mod v1.0.0 loading..."); PillBottlePrice = ((BaseUnityPlugin)this).Config.Bind("Shop", "Price", 60, "Cost of the Pill Bottle in the terminal store, in credits."); AddictionSecondsToMax = ((BaseUnityPlugin)this).Config.Bind("Addiction", "SecondsToMaxAddiction", 900f, "Seconds of not dosing to climb from 0% to 100% addiction. Default 900 (15 min). Set low (e.g. 30) to test the withdrawal debuffs quickly."); PillBottleEffectManager.AddictionSecondsToMax = AddictionSecondsToMax.Value; _harmony.PatchAll(); GameObject val = new GameObject("PillBottleHud"); val.AddComponent(); Log.LogInfo((object)"Pill Bottle Mod loaded successfully."); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "PillBottleMod"; public const string PLUGIN_NAME = "PillBottleMod"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace PillBottleMod.Items { public class PillBottleState { public float buffEndTime = -1f; public float hangoverEndTime = -1f; public float addictionLevel = 0f; public int totalDosesTaken = 0; public readonly List recentDoseTimes = new List(); public float nextAddictionDamageTick = -1f; public float staminaEndTime = -1f; public float baseMoveSpeed; public float baseJumpForce; public bool baseValuesCached = false; } public static class PillBottleEffectManager { private const float BuffDuration = 60f; private const float HangoverDuration = 180f; public static float AddictionSecondsToMax = 900f; private const int DosesBeforeAddictionStarts = 2; private const float OverdoseWindowSeconds = 60f; private const int OverdoseDoseThreshold = 3; private const float BuffSpeedMultiplier = 1.5f; private const float BuffJumpMultiplier = 1.4f; private const float HangoverSpeedMultiplier = 0.5f; private const float StaminaBoostDuration = 15f; private static readonly Dictionary States = new Dictionary(); public static bool LocalHasState = false; public static bool LocalBuffActive = false; public static bool LocalHangoverActive = false; public static float LocalAddiction = 0f; public static float LocalOverdose = 0f; public static bool LocalStaminaActive = false; private static PillBottleState GetOrCreateState(PlayerControllerB player) { if (!States.TryGetValue(player, out var value)) { value = new PillBottleState(); States[player] = value; } return value; } public static void TakeDose(PlayerControllerB player) { if (!((Object)(object)player == (Object)null)) { PillBottleState orCreateState = GetOrCreateState(player); float now = Time.time; CacheBaseValuesIfNeeded(player, orCreateState); orCreateState.recentDoseTimes.Add(now); orCreateState.recentDoseTimes.RemoveAll((float t) => now - t > 60f); if (orCreateState.recentDoseTimes.Count >= 3) { KillPlayerFromOverdose(player); return; } orCreateState.totalDosesTaken++; orCreateState.addictionLevel = 0f; orCreateState.buffEndTime = now + 60f; orCreateState.hangoverEndTime = -1f; orCreateState.staminaEndTime = now + 15f; Plugin.Log.LogInfo((object)$"[PillBottle] {player.playerUsername} took a dose. Total: {orCreateState.totalDosesTaken}, Addiction: {orCreateState.addictionLevel:F0}%"); } } private static void KillPlayerFromOverdose(PlayerControllerB player) { //IL_0022: 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_0032: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)("[PillBottle] " + player.playerUsername + " overdosed.")); player.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 0, default(Vector3), false); } private static void CacheBaseValuesIfNeeded(PlayerControllerB player, PillBottleState state) { if (!state.baseValuesCached) { state.baseMoveSpeed = player.movementSpeed; state.baseJumpForce = player.jumpForce; state.baseValuesCached = true; } } public static void Tick(PlayerControllerB player) { if (!((Object)(object)player == (Object)null) && States.TryGetValue(player, out var value) && value.baseValuesCached) { float time = Time.time; bool flag = value.totalDosesTaken > 2; bool flag2 = value.buffEndTime > time; if (flag && !flag2) { float num = 100f / Mathf.Max(1f, AddictionSecondsToMax); value.addictionLevel = Mathf.Clamp(value.addictionLevel + num * Time.deltaTime, 0f, 100f); } bool flag3 = value.buffEndTime > time; bool hangoverActive = !flag3 && value.hangoverEndTime > time; if (!flag3 && value.buffEndTime > 0f && value.hangoverEndTime < 0f) { value.hangoverEndTime = time + 180f; hangoverActive = true; value.buffEndTime = -1f; } if (value.hangoverEndTime > 0f && time > value.hangoverEndTime) { value.hangoverEndTime = -1f; hangoverActive = false; } ApplyMovementEffects(player, value, flag3, hangoverActive); ApplyAddictionEffects(player, value); ApplyScreenEffects(player, value, flag3, hangoverActive); } } private static void ApplyMovementEffects(PlayerControllerB player, PillBottleState state, bool buffActive, bool hangoverActive) { float num = 1f; float num2 = 1f; if (buffActive) { num *= 1.5f; num2 *= 1.4f; } else if (hangoverActive) { num *= 0.5f; } num *= GetAddictionSpeedMultiplier(state); player.movementSpeed = state.baseMoveSpeed * num; player.jumpForce = state.baseJumpForce * num2; if (state.staminaEndTime > Time.time) { player.sprintMeter = 1f; } } private static float GetAddictionSpeedMultiplier(PillBottleState state) { if (state.addictionLevel >= 100f) { return 0.15f; } if (state.addictionLevel >= 75f) { return 0.25f; } if (state.addictionLevel >= 50f) { return 0.45f; } if (state.addictionLevel >= 25f) { return 0.7f; } return 1f; } private static void ApplyAddictionEffects(PlayerControllerB player, PillBottleState state) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; if (state.addictionLevel >= 75f && Random.value < 0.15f * Time.deltaTime) { TryDropHeldItem(player); } if (state.addictionLevel >= 100f) { if (state.nextAddictionDamageTick < 0f) { state.nextAddictionDamageTick = time + 5f; } if (time >= state.nextAddictionDamageTick) { player.DamagePlayer(5, true, true, (CauseOfDeath)0, 0, false, default(Vector3)); state.nextAddictionDamageTick = time + 5f; } } else { state.nextAddictionDamageTick = -1f; } } private static void TryDropHeldItem(PlayerControllerB player) { //IL_0017: 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) if ((Object)(object)player.currentlyHeldObjectServer != (Object)null) { player.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true); } } private static void ApplyScreenEffects(PlayerControllerB player, PillBottleState state, bool buffActive, bool hangoverActive) { if (!((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)player != (Object)(object)StartOfRound.Instance.localPlayerController)) { float now = Time.time; state.recentDoseTimes.RemoveAll((float t) => now - t > 60f); float num = 0f; for (int num2 = 0; num2 < state.recentDoseTimes.Count; num2++) { float num3 = now - state.recentDoseTimes[num2]; num += Mathf.Clamp01(1f - num3 / 60f); } LocalHasState = true; LocalBuffActive = buffActive; LocalHangoverActive = hangoverActive; LocalAddiction = state.addictionLevel; LocalOverdose = Mathf.Clamp01(num / 3f); LocalStaminaActive = state.staminaEndTime > now; } } } [HarmonyPatch] public static class PillBottleSetup { public const string TargetItemName = "Pill Bottle"; private static bool _configured; public static Item PillBottleItem { get; private set; } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void StartOfRound_Awake_Postfix(StartOfRound __instance) { PillBottleHud.EnsureExists(); if (_configured || (Object)(object)__instance == (Object)null || (Object)(object)__instance.allItemsList == (Object)null || __instance.allItemsList.itemsList == null) { return; } Item val = ((IEnumerable)__instance.allItemsList.itemsList).FirstOrDefault((Func)((Item it) => (Object)(object)it != (Object)null && string.Equals(it.itemName, "Pill Bottle", StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)"[PillBottle] Could not find an item named \"Pill Bottle\". Dumping every item name so you can set TargetItemName to the exact string:"); { foreach (Item items in __instance.allItemsList.itemsList) { if ((Object)(object)items != (Object)null) { Plugin.Log.LogError((object)("[PillBottle] itemName = \"" + items.itemName + "\"")); } } return; } } PillBottleItem = val; int num = ((Plugin.PillBottlePrice != null) ? Plugin.PillBottlePrice.Value : 60); Items.RegisterShopItem(val, (TerminalNode)null, (TerminalNode)null, (TerminalNode)null, num); Plugin.Log.LogInfo((object)$"[PillBottle] Registered \"{val.itemName}\" in the store for {num} credits."); _configured = true; } } [HarmonyPatch] public static class PillBottlePatches { [HarmonyPatch(typeof(GrabbableObject), "ItemActivate")] [HarmonyPostfix] public static void GrabbableObject_ItemActivate_Postfix(GrabbableObject __instance, bool used, bool buttonDown) { if (buttonDown && !((Object)(object)__instance.itemProperties == (Object)null) && string.Equals(__instance.itemProperties.itemName, "Pill Bottle", StringComparison.OrdinalIgnoreCase)) { PlayerControllerB playerHeldBy = __instance.playerHeldBy; if (!((Object)(object)playerHeldBy == (Object)null) && !((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)playerHeldBy != (Object)(object)StartOfRound.Instance.localPlayerController)) { PillBottleEffectManager.TakeDose(playerHeldBy); playerHeldBy.DestroyItemInSlotAndSync(playerHeldBy.currentItemSlot); } } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPostfix] public static void PlayerControllerB_Update_Postfix(PlayerControllerB __instance) { PillBottleEffectManager.Tick(__instance); } } }