Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PillBottleMod v1.0.0
PillBottleMod.dll
Decompiled 21 hours agousing 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<PillBottleHud>(); } } 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<int> PillBottlePrice; internal static ConfigEntry<float> 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<int>("Shop", "Price", 60, "Cost of the Pill Bottle in the terminal store, in credits."); AddictionSecondsToMax = ((BaseUnityPlugin)this).Config.Bind<float>("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<PillBottleHud>(); 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<float> recentDoseTimes = new List<float>(); 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<PlayerControllerB, PillBottleState> States = new Dictionary<PlayerControllerB, PillBottleState>(); 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<Item>)__instance.allItemsList.itemsList).FirstOrDefault((Func<Item, bool>)((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); } } }