using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HBS;
using HarmonyLib;
using KoMiKoZa.Necropolis.JSONLocalizeAPI;
using Necro;
using Necro.Signaling;
using Necro.UI;
using UnityEngine;
[assembly: AssemblyConfiguration("")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyTitle("Quick Drop")]
[assembly: AssemblyDescription("Adds hotkeys to quickly drop items, gems, and tokens in Necropolis.")]
[assembly: AssemblyCompany("Komikoza")]
[assembly: AssemblyProduct("Quick Drop")]
[assembly: AssemblyCopyright("Copyright © 2025 Komikoza")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("00d4a42d-d280-48be-9825-aec6418c43e5")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Komikoza.Necropolis.QuickDrop;
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("komikoza.necropolis.quickdrop", "Quick Drop", "1.0.0")]
public class QuickDropPlugin : BaseUnityPlugin
{
private const string GUID = "komikoza.necropolis.quickdrop";
private const string NAME = "Quick Drop";
private const string VERSION = "1.0.0";
internal static ManualLogSource Logger;
internal static ConfigEntry<bool> ModEnabled;
internal static ConfigEntry<bool> DebugMode;
internal static ConfigEntry<bool> EnableItems;
internal static ConfigEntry<bool> EnableGems;
internal static ConfigEntry<bool> EnableTokens;
internal static ConfigEntry<KeyCode> ItemDropKey;
internal static ConfigEntry<KeyCode> GemDropKey;
internal static ConfigEntry<KeyCode> TokenDropKey;
internal static ConfigEntry<bool> ShowDropToast;
internal static ConfigEntry<int> GemDropAmount;
internal static ConfigEntry<string> TokenCurrencyID;
internal static List<Vector3> PlayerGemDropPositions = new List<Vector3>();
private void Awake()
{
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Expected O, but got Unknown
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Unknown result type (might be due to invalid IL or missing references)
//IL_0245: Unknown result type (might be due to invalid IL or missing references)
Logger = ((BaseUnityPlugin)this).Logger;
ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ModEnabled", true, "Enable or disable this mod");
DebugMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugMode", false, "Enable debug logging");
EnableItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Features", "EnableItems", true, "Enable quick drop for items");
EnableGems = ((BaseUnityPlugin)this).Config.Bind<bool>("Features", "EnableGems", true, "Enable quick drop for gems");
EnableTokens = ((BaseUnityPlugin)this).Config.Bind<bool>("Features", "EnableTokens", true, "Enable quick drop for tokens");
ItemDropKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybindings", "ItemDropKey", (KeyCode)103, "Key to quickly drop the active inventory item");
GemDropKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybindings", "GemDropKey", (KeyCode)98, "Key to quickly drop gems");
TokenDropKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybindings", "TokenDropKey", (KeyCode)110, "Key to quickly drop one token");
ShowDropToast = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowDropToast", true, "Show toast notifications when dropping items");
GemDropAmount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "GemDropAmount", 100, "Amount of gems to drop each time (0 = drop all gems)");
TokenCurrencyID = ((BaseUnityPlugin)this).Config.Bind<string>("Advanced", "TokenCurrencyID", "Token", "The currency ID for tokens (only change if mod doesn't work)");
if (!ModEnabled.Value)
{
Logger.LogInfo((object)string.Format("[{0}] Disabled", "Quick Drop"));
return;
}
try
{
Harmony val = new Harmony("komikoza.necropolis.quickdrop");
val.PatchAll();
Logger.LogInfo((object)"================================================");
Logger.LogInfo((object)string.Format("[{0}] v{1} loaded!", "Quick Drop", "1.0.0"));
Logger.LogInfo((object)string.Concat(" - Press ", ItemDropKey.Value, " to drop items"));
Logger.LogInfo((object)string.Concat(" - Press ", GemDropKey.Value, " to drop gems"));
Logger.LogInfo((object)string.Concat(" - Press ", TokenDropKey.Value, " to drop tokens"));
Logger.LogInfo((object)"================================================");
}
catch (Exception arg)
{
Logger.LogError((object)string.Format("[{0}] Failed to load: {1}", "Quick Drop", arg));
}
}
}
[HarmonyPatch(typeof(ThirdPersonCameraControl), "Update")]
internal static class ThirdPersonCameraControl_Update_Patch
{
private static void Postfix(ThirdPersonCameraControl __instance)
{
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
try
{
if (QuickDropPlugin.ModEnabled.Value && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.Inventory == (Object)null) && !((Object)(object)__instance.CharacterActor == (Object)null) && !LazySingletonBehavior<UIManager>.Instance.IsMenusActive && !__instance.CharacterActor.IsUsingItem)
{
if (QuickDropPlugin.EnableItems.Value && Input.GetKeyDown(QuickDropPlugin.ItemDropKey.Value))
{
ProcessQuickDropItem(__instance);
}
if (QuickDropPlugin.EnableGems.Value && Input.GetKeyDown(QuickDropPlugin.GemDropKey.Value))
{
ProcessQuickDropGems(__instance);
}
if (QuickDropPlugin.EnableTokens.Value && Input.GetKeyDown(QuickDropPlugin.TokenDropKey.Value))
{
ProcessQuickDropTokens(__instance);
}
}
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] Update patch error: " + ex));
}
}
private static void ProcessQuickDropItem(ThirdPersonCameraControl instance)
{
try
{
Inventory inventory = instance.Inventory;
Actor characterActor = instance.CharacterActor;
Item activeItemFromBone = inventory.GetActiveItemFromBone("ITEM_SLOT", true);
if (activeItemFromBone == null)
{
if (QuickDropPlugin.DebugMode.Value)
{
QuickDropPlugin.Logger.LogInfo((object)"[Quick Drop][DEBUG] No active item to drop");
}
return;
}
if (!inventory.CanDrop(activeItemFromBone.def))
{
if (QuickDropPlugin.DebugMode.Value)
{
QuickDropPlugin.Logger.LogInfo((object)("[Quick Drop][DEBUG] Cannot drop this item: " + activeItemFromBone.def.id));
}
AudioBankManager.Instance.audioUIDeny.PostEvent();
return;
}
if (!characterActor.TryUseItem())
{
if (QuickDropPlugin.DebugMode.Value)
{
QuickDropPlugin.Logger.LogInfo((object)"[Quick Drop][DEBUG] Actor busy, cannot drop now");
}
return;
}
string arg = Strings.T(inventory.GetItemString(activeItemFromBone.def, (ItemTextType)0, (string)null), (string)null);
inventory.Drop(activeItemFromBone.def);
if (QuickDropPlugin.DebugMode.Value)
{
QuickDropPlugin.Logger.LogInfo((object)("[Quick Drop][DEBUG] Dropped: " + activeItemFromBone.def.id));
}
if (QuickDropPlugin.ShowDropToast.Value && LazySingletonBehavior<UIManager>.HasInstance)
{
string fromObject = JSONLocalizeAPI.GetFromObject(Assembly.GetExecutingAssembly(), "drop_single", "Dropped: {0}");
string text = string.Format(fromObject, arg);
LazySingletonBehavior<UIManager>.Instance.CreateToast(text, (string)null, (object[])null);
}
AudioBankManager.Instance.audioUISelect.PostEvent();
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] Item drop error: " + ex));
}
}
private static void ProcessQuickDropGems(ThirdPersonCameraControl instance)
{
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
try
{
Inventory inventory = instance.Inventory;
Actor characterActor = instance.CharacterActor;
int currency = inventory.GetCurrency("Gem1");
if (currency <= 0)
{
AudioBankManager.Instance.audioUIDeny.PostEvent();
return;
}
int num = QuickDropPlugin.GemDropAmount.Value;
if (num <= 0 || currency < num)
{
num = currency;
}
if (characterActor.TryUseItem())
{
inventory.RemoveCurrency("Gem1", num);
Transform transform = ((Component)characterActor).transform;
Vector3 val = transform.position + transform.forward * 1.5f;
Quaternion rotation = transform.rotation;
QuickDropPlugin.PlayerGemDropPositions.Add(val);
ItemDrop.CreateGemDrop(val, rotation, num, (ItemDropType)3);
if (QuickDropPlugin.DebugMode.Value)
{
QuickDropPlugin.Logger.LogInfo((object)("[Quick Drop][DEBUG] Dropped " + num + " gems"));
}
if (QuickDropPlugin.ShowDropToast.Value && LazySingletonBehavior<UIManager>.HasInstance)
{
string arg = Strings.T("CURRENCY_GEMS", (string)null);
string fromObject = JSONLocalizeAPI.GetFromObject(Assembly.GetExecutingAssembly(), "drop_multiple", "Dropped: {0} x {1}");
string text = string.Format(fromObject, arg, num);
LazySingletonBehavior<UIManager>.Instance.CreateToast(text, (string)null, (object[])null);
}
AudioBankManager.Instance.audioUISelect.PostEvent();
}
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] Gem drop error: " + ex));
}
}
private static void ProcessQuickDropTokens(ThirdPersonCameraControl instance)
{
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: 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)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Expected O, but got Unknown
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
try
{
Inventory inventory = instance.Inventory;
Actor characterActor = instance.CharacterActor;
string value = QuickDropPlugin.TokenCurrencyID.Value;
int currency = inventory.GetCurrency(value);
if (currency <= 0)
{
AudioBankManager.Instance.audioUIDeny.PostEvent();
return;
}
int num = 1;
if (!characterActor.TryUseItem())
{
return;
}
inventory.RemoveCurrency(value, num);
Transform transform = ((Component)characterActor).transform;
Vector3 val = transform.position + transform.forward * 1.5f;
Quaternion rotation = transform.rotation;
ItemDef val2 = LazySingletonBehavior<DataManager>.Instance.Items.Get(value);
if (val2 == null)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] Token currency ID '" + value + "' not found! Check your config."));
inventory.AddCurrency(value, num, true);
AudioBankManager.Instance.audioUIDeny.PostEvent();
return;
}
Item val3 = new Item(val2);
val3.intValue = num;
ItemDrop.CreateItemDrop(val, rotation, val3, (ItemDropType)3, true, true);
if (QuickDropPlugin.DebugMode.Value)
{
QuickDropPlugin.Logger.LogInfo((object)"[Quick Drop][DEBUG] Dropped 1 token");
}
if (QuickDropPlugin.ShowDropToast.Value && LazySingletonBehavior<UIManager>.HasInstance)
{
string arg = Strings.T("STATS_TOKENS", (string)null);
string fromObject = JSONLocalizeAPI.GetFromObject(Assembly.GetExecutingAssembly(), "drop_single", "Dropped: {0}");
string text = string.Format(fromObject, arg);
LazySingletonBehavior<UIManager>.Instance.CreateToast(text, (string)null, (object[])null);
}
AudioBankManager.Instance.audioUISelect.PostEvent();
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] Token drop error: " + ex));
}
}
}
[HarmonyPatch(typeof(RxEquipmentSwap), "Activate")]
internal static class RxEquipmentSwap_Activate_Patch
{
private static FieldInfo cachedItemDropField = null;
private static Vector3 matchedPosition;
private static void Prefix(RxEquipmentSwap __instance, ref float __state)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Invalid comparison between Unknown and I4
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
try
{
if (!QuickDropPlugin.ModEnabled.Value || !QuickDropPlugin.EnableGems.Value)
{
return;
}
__state = Actor.TreasureHunterTraitValue;
matchedPosition = Vector3.zero;
if ((Object)(object)__instance == (Object)null)
{
return;
}
if ((object)cachedItemDropField == null)
{
cachedItemDropField = typeof(RxEquipmentSwap).GetField("itemDrop", BindingFlags.Instance | BindingFlags.NonPublic);
}
if ((object)cachedItemDropField == null)
{
return;
}
object? value = cachedItemDropField.GetValue(__instance);
ItemDrop val = (ItemDrop)((value is ItemDrop) ? value : null);
if ((Object)(object)val == (Object)null || val.Item == null || (int)val.Item.def.kind != 9)
{
return;
}
Vector3 position = ((Component)val).transform.position;
for (int i = 0; i < QuickDropPlugin.PlayerGemDropPositions.Count; i++)
{
Vector3 val2 = QuickDropPlugin.PlayerGemDropPositions[i];
if (Vector3.Distance(position, val2) < 3f)
{
Actor.TreasureHunterTraitValue = 1f;
matchedPosition = val2;
if (QuickDropPlugin.DebugMode.Value)
{
QuickDropPlugin.Logger.LogInfo((object)"[Quick Drop][DEBUG] Bypassing TreasureHunter for player-dropped gem");
}
break;
}
}
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] RxEquipmentSwap Prefix error: " + ex));
}
}
private static void Postfix(float __state)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
try
{
if (QuickDropPlugin.ModEnabled.Value)
{
Actor.TreasureHunterTraitValue = __state;
if (matchedPosition != Vector3.zero)
{
QuickDropPlugin.PlayerGemDropPositions.Remove(matchedPosition);
}
}
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] RxEquipmentSwap Postfix error: " + ex));
}
}
}
[HarmonyPatch(typeof(ItemDrop), "Awake")]
internal static class ItemDrop_Awake_Patch
{
private static void Postfix(ItemDrop __instance)
{
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Invalid comparison between Unknown and I4
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Invalid comparison between Unknown and I4
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Expected O, but got Unknown
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
try
{
if (!QuickDropPlugin.ModEnabled.Value || !QuickDropPlugin.EnableTokens.Value)
{
return;
}
FieldInfo field = typeof(ItemDrop).GetField("itemDropTypeList", BindingFlags.Instance | BindingFlags.NonPublic);
if ((object)field == null || !(field.GetValue(__instance) is List<ItemDropInfo> list))
{
return;
}
bool flag = false;
foreach (ItemDropInfo item in list)
{
if ((int)item.kind == 17)
{
flag = true;
break;
}
}
if (flag)
{
return;
}
ItemDropInfo val = null;
foreach (ItemDropInfo item2 in list)
{
if ((int)item2.kind == 9)
{
val = item2;
break;
}
}
if (val != null)
{
ItemDropInfo val2 = new ItemDropInfo();
val2.kind = (Kind)17;
val2.pickupAudioEvent = val.pickupAudioEvent;
val2.dropAudioEvent = val.dropAudioEvent;
list.Add(val2);
if (QuickDropPlugin.DebugMode.Value)
{
QuickDropPlugin.Logger.LogInfo((object)"[Quick Drop][DEBUG] Added PersistentCurrency support to ItemDrop");
}
}
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] ItemDrop_Awake error: " + ex));
}
}
}
[HarmonyPatch(typeof(Strings), "T", new Type[]
{
typeof(string),
typeof(string)
})]
internal static class Strings_T_Patch
{
private static bool isProcessing = false;
private static string cachedTokenName = null;
private static bool Prefix(string str, ref string __result)
{
try
{
if (!QuickDropPlugin.ModEnabled.Value)
{
return true;
}
if (!QuickDropPlugin.EnableTokens.Value)
{
return true;
}
if (isProcessing)
{
return true;
}
if (str != null && str.StartsWith("Token/"))
{
if (cachedTokenName == null)
{
isProcessing = true;
cachedTokenName = Strings.T("STATS_TOKENS", (string)null);
isProcessing = false;
}
__result = cachedTokenName;
return false;
}
return true;
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] Strings_T error: " + ex));
return true;
}
}
}
[HarmonyPatch(typeof(Inventory), "GetItemString")]
internal static class Inventory_GetItemString_Patch
{
private static bool isProcessing = false;
private static string cachedTokenName = null;
private static void Postfix(ItemDef item, ItemTextType type, ref string __result)
{
try
{
if (QuickDropPlugin.ModEnabled.Value && QuickDropPlugin.EnableTokens.Value && !isProcessing && __result != null && __result.StartsWith("Token/"))
{
if (cachedTokenName == null)
{
isProcessing = true;
cachedTokenName = Strings.T("STATS_TOKENS", (string)null);
isProcessing = false;
}
__result = cachedTokenName;
}
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] GetItemString error: " + ex));
}
}
}
[HarmonyPatch(typeof(Inventory), "Pickup")]
internal static class Inventory_Pickup_Patch
{
private static FieldInfo selfField = null;
private static void Prefix(Inventory __instance, Item item, ref bool quiet)
{
try
{
if (!QuickDropPlugin.ModEnabled.Value || !QuickDropPlugin.EnableTokens.Value)
{
return;
}
if ((object)selfField == null)
{
selfField = typeof(Inventory).GetField("self", BindingFlags.Instance | BindingFlags.NonPublic);
}
if ((object)selfField != null)
{
object? value = selfField.GetValue(__instance);
Actor val = (Actor)((value is Actor) ? value : null);
if (item != null && item.def != null && item.def.id == "Token" && (Object)(object)val != (Object)null && val.IsLocalPlayer)
{
quiet = true;
}
}
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] Pickup Prefix error: " + ex));
}
}
private static void Postfix(Inventory __instance, Item item, bool __result)
{
try
{
if (!QuickDropPlugin.ModEnabled.Value || !QuickDropPlugin.EnableTokens.Value || !__result)
{
return;
}
if ((object)selfField == null)
{
selfField = typeof(Inventory).GetField("self", BindingFlags.Instance | BindingFlags.NonPublic);
}
if ((object)selfField == null)
{
return;
}
object? value = selfField.GetValue(__instance);
Actor val = (Actor)((value is Actor) ? value : null);
if (item != null && item.def != null && item.def.id == "Token" && (Object)(object)val != (Object)null && val.IsLocalPlayer)
{
string arg = Strings.T("STATS_TOKENS", (string)null);
string text = ((item.intValue > 1) ? "PickUpItemMultiple_001" : "PickUpItemSingle_001");
string format = Strings.T(text, (string)null);
string text2 = ((item.intValue <= 1) ? string.Format(format, arg) : string.Format(format, arg, item.intValue));
if (LazySingletonBehavior<UIManager>.HasInstance)
{
LazySingletonBehavior<UIManager>.Instance.CreateToast(text2, (string)null, (object[])null);
}
if (AudioBankManager.HasInstance)
{
AudioBankManager.Instance.tokenPurchased.PostEvent();
}
}
}
catch (Exception ex)
{
QuickDropPlugin.Logger.LogError((object)("[Quick Drop] Pickup Postfix error: " + ex));
}
}
}