using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using PerfectRandom.Sulfur.Core; using PerfectRandom.Sulfur.Core.Items; using PerfectRandom.Sulfur.Core.UI; using PerfectRandom.Sulfur.Core.UI.Inventory; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("RandomWeaponPerLevel")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RandomWeaponPerLevel")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("2c8445fc-70f2-4406-be3e-d54a3e8b4737")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace RandomWeaponPerLevel; public enum PreferredWeaponSlotMode { Weapon0, Weapon1, Random, FirstAvailable } public sealed class RandomWeaponMarker : MonoBehaviour { public int generationId; public int levelSignature; public string reason; public string weaponName; } [BepInPlugin("kumo.sulfur.random_weapon_per_level", "Random Weapon Per Level", "0.4.1")] public sealed class Plugin : BaseUnityPlugin { private sealed class WeightedAttachmentCandidate { public ItemDefinition Item; public float Weight; public WeightedAttachmentCandidate(ItemDefinition item, float weight) { Item = item; Weight = weight; } } [CompilerGenerated] private sealed class d__78 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public int signature; public string reason; public Plugin <>4__this; private float 5__1; private int 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__78(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this.autoGiveRoutineRunning = true; 5__1 = Mathf.Max(0f, <>4__this.autoGiveDelayAfterLevelStart.Value); if (5__1 > 0f) { <>2__current = (object)new WaitForSeconds(5__1); <>1__state = 1; return true; } goto IL_008c; case 1: <>1__state = -1; goto IL_008c; case 2: { <>1__state = -1; <>4__this.autoGiveRoutineRunning = false; return false; } IL_008c: if (!<>4__this.enableMod.Value || !<>4__this.randomizeOnLevelStart.Value) { <>4__this.autoGivenLevelSignatures.Remove(signature); <>4__this.autoGiveRoutineRunning = false; return false; } if (!<>4__this.IsInPlayableLevel()) { <>4__this.autoGivenLevelSignatures.Remove(signature); <>4__this.sawLoadingOrLevelTransition = true; <>4__this.autoGiveRoutineRunning = false; return false; } 5__2 = <>4__this.GetCachedLevelSignature(); if (5__2 != signature) { <>4__this.autoGivenLevelSignatures.Remove(signature); <>4__this.sawLoadingOrLevelTransition = true; <>4__this.autoGiveRoutineRunning = false; return false; } <>2__current = <>4__this.GiveRandomWeaponRoutine(reason + " " + signature, signature); <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__82 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string reason; public int levelSignature; public Plugin <>4__this; private ItemGrid 5__1; private WeaponSO 5__2; private InventorySlot 5__3; private HashSet 5__4; private int 5__5; private InventoryItem 5__6; private int 5__7; private Exception 5__8; private int 5__9; private int 5__10; private int 5__11; private int 5__12; private string 5__13; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__82(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; 5__2 = null; 5__4 = null; 5__6 = null; 5__8 = null; 5__13 = null; <>1__state = -2; } private bool MoveNext() { //IL_0191: 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_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Invalid comparison between Unknown and I4 //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = <>4__this.GetPlayerBackpackGrid(); if ((Object)(object)5__1 == (Object)null) { ((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"Could not give random weapon: PlayerBackpackGrid is null."); return false; } 5__2 = <>4__this.PickRandomWeapon(); if ((Object)(object)5__2 == (Object)null) { ((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"Could not give random weapon: no valid WeaponSO found."); return false; } if (<>4__this.cleanupOldGeneratedWeapons.Value) { 5__7 = <>4__this.CleanupOldGeneratedWeapons(null); if (5__7 > 0 && <>4__this.logActions.Value) { ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("Removed old generated weapons before generating a new one: " + 5__7)); } <>2__current = null; <>1__state = 1; return true; } goto IL_0139; case 1: <>1__state = -1; goto IL_0139; case 2: <>1__state = -1; if (!<>4__this.IsWeaponSlotEmpty(5__3)) { ((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)("Could not give random weapon: target slot is still occupied: " + ((object)(InventorySlot)(ref 5__3)).ToString())); return false; } 5__4 = <>4__this.CapturePlayerInventoryItems(); try { StaticInstance.Instance.InventoryUI.SpawnItemInSlot((ItemDefinition)(object)5__2, 5__3, (InventoryData)null); if (<>4__this.announcePickup.Value && (Object)(object)5__1 != (Object)null) { try { 5__1.PlayPickupNote((ItemDefinition)(object)5__2, (int?)null); } catch { } } } catch (Exception ex) { 5__8 = ex; ((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)("Failed to spawn random weapon " + GetWeaponName(5__2) + " into " + ((object)(InventorySlot)(ref 5__3)).ToString() + ": " + 5__8.Message)); return false; } 5__5 = Mathf.Clamp(<>4__this.postCreateWaitFrames.Value, 1, 60); 5__9 = 0; break; case 3: { <>1__state = -1; 5__9++; break; } IL_0139: 5__3 = <>4__this.PrepareTargetWeaponSlot(); if ((int)5__3 == 9) { ((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"Could not give random weapon: no usable Weapon0/Weapon1 slot. Backpack may be full."); return false; } <>2__current = null; <>1__state = 2; return true; } if (5__9 < 5__5) { <>2__current = null; <>1__state = 3; return true; } 5__6 = <>4__this.FindNewInventoryItem(5__4, 5__2); if ((Object)(object)5__6 == (Object)null) { 5__6 = <>4__this.GetItemInWeaponSlot(5__3); } if ((Object)(object)5__6 != (Object)null) { <>4__this.MarkGeneratedWeapon(5__6, reason, levelSignature); if (<>4__this.forceSelectGeneratedWeapon.Value) { <>4__this.TrySelectWeaponSlot(5__3); } 5__10 = <>4__this.ApplyRandomOilsIfNeeded(5__6); 5__11 = <>4__this.ApplyRandomScrollsIfNeeded(5__6); <>4__this.GrantMinimumRankForAppliedEnchantments(5__6, 5__10 + 5__11); <>4__this.TrySyncInstancedWeapon(5__6); 5__12 = <>4__this.ApplyRandomAttachmentsIfNeeded(5__6); <>4__this.TrySyncInstancedWeapon(5__6); <>4__this.NormalizeDurabilityIfNeeded(5__6); <>4__this.FixDurabilityIfNeeded(5__6); <>4__this.TrySyncInstancedWeapon(5__6); if (<>4__this.forceSelectGeneratedWeapon.Value) { <>4__this.TrySelectWeaponSlot(5__3); } if (<>4__this.cleanupOldGeneratedWeapons.Value) { <>4__this.CleanupOldGeneratedWeapons(5__6); } } if (<>4__this.logActions.Value) { 5__13 = (((Object)(object)5__6 != (Object)null) ? <>4__this.BuildCreatedItemInfo(5__6) : "created item not found after SpawnItemInSlot"); ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("Generated random weapon by " + reason + " into " + ((object)(InventorySlot)(ref 5__3)).ToString() + ": " + GetWeaponName(5__2) + " (" + 5__13 + ")")); 5__13 = null; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal static ManualLogSource Log; internal static Plugin Instance; private Harmony harmony; private ConfigEntry enableMod; private ConfigEntry randomizeOnLevelStart; private ConfigEntry debugKeyEnabled; private ConfigEntry debugKey; private int lastTransitionCleanupFrame = -1; private ConfigEntry preferredWeaponSlot; private ConfigEntry forceSelectGeneratedWeapon; private ConfigEntry cleanupOldGeneratedWeapons; private ConfigEntry destroyGeneratedWeaponsOnDrop; private ConfigEntry cleanupGeneratedWeaponsBeforeLevelTransition; private ConfigEntry gunsOnly; private ConfigEntry excludeStartsEmpty; private ConfigEntry requireWeaponPrefab; private ConfigEntry requireAmmoMagazine; private ConfigEntry requireUsableByPlayer; private ConfigEntry enableRandomOils; private ConfigEntry minOilCount; private ConfigEntry maxOilCount; private ConfigEntry respectEnchantmentSlots; private ConfigEntry grantRankForAppliedOils; private ConfigEntry enableRandomScrolls; private ConfigEntry scrollChance; private ConfigEntry minScrollCount; private ConfigEntry maxScrollCount; private ConfigEntry enableRandomWeaponOnKill; private ConfigEntry randomWeaponOnKillCooldown; private ConfigEntry killRewardRequiresPlayableLevel; private ConfigEntry killRewardRequireExperienceOnKill; private ConfigEntry logKillRewardChecks; private float nextKillRewardAllowedTime; private readonly HashSet rewardedKillUnitIds = new HashSet(); private ConfigEntry enableRandomAttachments; private ConfigEntry attachmentChance; private ConfigEntry minAttachmentCount; private ConfigEntry maxAttachmentCount; private ConfigEntry minimumDurabilityNormalized; private ConfigEntry fixLowDurability; private ConfigEntry announcePickup; private ConfigEntry logActions; private ConfigEntry logWeaponPool; private ConfigEntry autoGiveDelayAfterLevelStart; private ConfigEntry postCreateWaitFrames; private ConfigEntry sceneSignatureCheckInterval; private readonly List cachedWeaponPool = new List(); private readonly HashSet autoGivenLevelSignatures = new HashSet(); private bool sawLoadingOrLevelTransition; private bool autoGiveRoutineRunning; private int currentLevelSignature; private int cachedLevelSignature; private float nextSignatureCheckTime; private int generationCounter; internal int CleanupGeneratedWeaponsForTransition(string reason) { if (!ShouldCleanupBeforeLevelTransition()) { return 0; } if (lastTransitionCleanupFrame == Time.frameCount) { return 0; } lastTransitionCleanupFrame = Time.frameCount; int num = CleanupOldGeneratedWeapons(null); if (num > 0) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("Removed generated weapon(s) before transition: " + num + " (" + reason + ")")); } } else if (logActions != null && logActions.Value) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)("Transition cleanup checked, no generated weapon found. (" + reason + ")")); } } return num; } private void Awake() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Expected O, but got Unknown //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Expected O, but got Unknown //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Expected O, but got Unknown //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Expected O, but got Unknown //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_04c8: Expected O, but got Unknown //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Expected O, but got Unknown //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Expected O, but got Unknown //IL_0581: Unknown result type (might be due to invalid IL or missing references) //IL_058b: Expected O, but got Unknown //IL_05b3: Unknown result type (might be due to invalid IL or missing references) //IL_05bd: Expected O, but got Unknown //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05ef: Expected O, but got Unknown //IL_0644: Unknown result type (might be due to invalid IL or missing references) //IL_064e: Expected O, but got Unknown //IL_066b: Unknown result type (might be due to invalid IL or missing references) //IL_0675: Expected O, but got Unknown //IL_071a: Unknown result type (might be due to invalid IL or missing references) //IL_071f: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Instance = this; enableMod = ((BaseUnityPlugin)this).Config.Bind("General", "EnableMod", true, "Enable this mod."); randomizeOnLevelStart = ((BaseUnityPlugin)this).Config.Bind("General", "RandomizeOnLevelStart", true, "Give one random weapon when entering a non-safe-zone level."); enableRandomWeaponOnKill = ((BaseUnityPlugin)this).Config.Bind("Kill Reward", "EnableRandomWeaponOnKill", true, "If true, killing an eligible enemy grants one generated random weapon."); randomWeaponOnKillCooldown = ((BaseUnityPlugin)this).Config.Bind("Kill Reward", "RandomWeaponOnKillCooldown", 1f, new ConfigDescription("Cooldown in seconds for random weapon rewards from enemy kills.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 30f), Array.Empty())); killRewardRequiresPlayableLevel = ((BaseUnityPlugin)this).Config.Bind("Kill Reward", "KillRewardRequiresPlayableLevel", true, "If true, kill rewards only trigger in playable non-safe-zone levels."); killRewardRequireExperienceOnKill = ((BaseUnityPlugin)this).Config.Bind("Kill Reward", "KillRewardRequireExperienceOnKill", true, "If true, only units with ExperienceOnKill > 0 can trigger a random weapon reward. This avoids most props and non-enemy objects."); logKillRewardChecks = ((BaseUnityPlugin)this).Config.Bind("Kill Reward", "LogKillRewardChecks", false, "Log detailed kill reward checks. Keep false for normal gameplay."); nextKillRewardAllowedTime = 0f; announcePickup = ((BaseUnityPlugin)this).Config.Bind("General", "AnnouncePickup", true, "Show pickup notification when a random weapon is generated."); preferredWeaponSlot = ((BaseUnityPlugin)this).Config.Bind("General", "PreferredWeaponSlot", PreferredWeaponSlotMode.FirstAvailable, "Which weapon slot should receive the generated weapon."); forceSelectGeneratedWeapon = ((BaseUnityPlugin)this).Config.Bind("General", "ForceSelectGeneratedWeapon", true, "Force-select the generated weapon after it is equipped."); cleanupOldGeneratedWeapons = ((BaseUnityPlugin)this).Config.Bind("General", "CleanupOldGeneratedWeapons", true, "Remove older runtime-tagged weapons generated by this mod before generating a new one."); cleanupGeneratedWeaponsBeforeLevelTransition = ((BaseUnityPlugin)this).Config.Bind("Safety", "CleanupGeneratedWeaponsBeforeLevelTransition", true, "Remove runtime-tagged generated weapons before GameManager.SwitchLevel runs. This prevents generated weapons from entering cross-level equipment data."); destroyGeneratedWeaponsOnDrop = ((BaseUnityPlugin)this).Config.Bind("Safety", "DestroyGeneratedWeaponsOnDrop", true, "Destroy runtime-tagged generated weapons when the player tries to drop them. This prevents tag loss through ground pickup data."); autoGiveDelayAfterLevelStart = ((BaseUnityPlugin)this).Config.Bind("Timing", "AutoGiveDelayAfterLevelStart", 2f, "Delay before giving the level-start random weapon after entering a playable level."); postCreateWaitFrames = ((BaseUnityPlugin)this).Config.Bind("Timing", "PostCreateWaitFrames", 8, new ConfigDescription("Frames to wait after SpawnItemInSlot before searching for the created InventoryItem.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 60), Array.Empty())); sceneSignatureCheckInterval = ((BaseUnityPlugin)this).Config.Bind("Timing", "SceneSignatureCheckInterval", 0.5f, new ConfigDescription("How often the mod checks the current level signature.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 5f), Array.Empty())); debugKeyEnabled = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugKeyEnabled", false, "Enable debug key spawning."); debugKey = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugKey", (Key)25, "Press this key to generate one random debug weapon. This can be used repeatedly."); logActions = ((BaseUnityPlugin)this).Config.Bind("Debug", "LogActions", true, "Log generated weapon information."); logWeaponPool = ((BaseUnityPlugin)this).Config.Bind("Debug", "LogWeaponPool", false, "Log every weapon in the random pool. Keep false unless debugging."); gunsOnly = ((BaseUnityPlugin)this).Config.Bind("Random Pool", "GunsOnly", true, "Exclude melee and throwable weapons."); excludeStartsEmpty = ((BaseUnityPlugin)this).Config.Bind("Random Pool", "ExcludeStartsEmpty", true, "Exclude weapons marked as startsEmpty."); requireWeaponPrefab = ((BaseUnityPlugin)this).Config.Bind("Random Pool", "RequireWeaponPrefab", true, "Only include weapons with a prefab. Recommended."); requireAmmoMagazine = ((BaseUnityPlugin)this).Config.Bind("Random Pool", "RequireAmmoMagazine", true, "Only include weapons with iAmmoMax > 0."); requireUsableByPlayer = ((BaseUnityPlugin)this).Config.Bind("Random Pool", "RequireUsableByPlayer", true, "Only include WeaponSO.usableByPlayer weapons."); enableRandomOils = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "EnableRandomOils", true, "Add random oil enchantments to generated weapons."); minOilCount = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "MinOilCount", 1, new ConfigDescription("Minimum random oil enchantments added to generated weapons.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 5), Array.Empty())); maxOilCount = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "MaxOilCount", 5, new ConfigDescription("Maximum random oil enchantments added to generated weapons.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 5), Array.Empty())); respectEnchantmentSlots = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "RespectEnchantmentSlots", false, "If true, only add oils/scrolls when the weapon has free enchantment slots. If false, this mod can create chaos guns regardless of rank."); grantRankForAppliedOils = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "GrantRankForAppliedOils", true, "If true, generated weapons gain enough XP to match the total applied enchantment count."); enableRandomScrolls = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "EnableRandomScrolls", true, "Add random scroll enchantments to generated weapons."); scrollChance = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "ScrollChance", 0.5f, new ConfigDescription("Chance for a generated weapon to receive scroll enchantments. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); minScrollCount = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "MinScrollCount", 1, new ConfigDescription("Minimum scroll enchantments if scroll generation succeeds.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 5), Array.Empty())); maxScrollCount = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "MaxScrollCount", 2, new ConfigDescription("Maximum scroll enchantments if scroll generation succeeds.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 5), Array.Empty())); enableRandomAttachments = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "EnableRandomAttachments", true, "Add random compatible attachments to generated weapons."); attachmentChance = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "AttachmentChance", 0.6f, new ConfigDescription("Chance for a generated weapon to receive attachments. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); minAttachmentCount = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "MinAttachmentCount", 1, new ConfigDescription("Minimum attachments if attachment generation succeeds.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); maxAttachmentCount = ((BaseUnityPlugin)this).Config.Bind("Random Upgrades", "MaxAttachmentCount", 2, new ConfigDescription("Maximum attachments if attachment generation succeeds.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); fixLowDurability = ((BaseUnityPlugin)this).Config.Bind("Safety", "FixLowDurability", true, "Raise generated weapon durability to MinimumDurabilityNormalized if it is lower."); minimumDurabilityNormalized = ((BaseUnityPlugin)this).Config.Bind("Safety", "MinimumDurabilityNormalized", 0.5f, new ConfigDescription("Minimum durability for generated weapons. 0.5 = at least 50%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); SceneManager.sceneLoaded += OnSceneLoaded; harmony = new Harmony("kumo.sulfur.random_weapon_per_level"); TryPatchHarmony(); sawLoadingOrLevelTransition = true; currentLevelSignature = 0; cachedLevelSignature = 0; nextSignatureCheckTime = 0f; generationCounter = 0; ManualLogSource logger = ((BaseUnityPlugin)this).Logger; string[] obj = new string[10] { "Random Weapon Per Level 0.4.2 loaded. EnableMod=", enableMod.Value.ToString(), ", RandomizeOnLevelStart=", randomizeOnLevelStart.Value.ToString(), ", DebugKeyEnabled=", debugKeyEnabled.Value.ToString(), ", DebugKey=", null, null, null }; Key value = debugKey.Value; obj[7] = ((object)(Key)(ref value)).ToString(); obj[8] = ", PreferredWeaponSlot="; obj[9] = preferredWeaponSlot.Value.ToString(); logger.LogInfo((object)string.Concat(obj)); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { sawLoadingOrLevelTransition = true; currentLevelSignature = 0; cachedLevelSignature = 0; nextSignatureCheckTime = 0f; rewardedKillUnitIds.Clear(); if (logActions != null && logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name + ". Auto-give transition armed.")); } } private void TryPatchHarmony() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(InventoryItem), "DropFromPlayer", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(GeneratedWeaponDropFromPlayerHook), "Prefix", (Type[])null, (Type[])null); if (methodInfo != null && methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched InventoryItem.DropFromPlayer."); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not patch InventoryItem.DropFromPlayer."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch InventoryItem.DropFromPlayer: " + ex.Message)); } TryPatchLevelTransitionMethods(); TryPatchNextLevelTrigger(); TryPatchAmuletHelper(); TryPatchUnitDie(); } private void TryPatchUnitDie() { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("PerfectRandom.Sulfur.Core.Units.Unit"); if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find Unit type for kill reward patch."); return; } MethodInfo methodInfo = AccessTools.Method(typeof(UnitDieRandomWeaponRewardHook), "Prefix", (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find UnitDieRandomWeaponRewardHook.Prefix."); return; } int num = 0; MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2 == null) && !(methodInfo2.Name != "Die")) { try { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched Unit.Die for random weapon on kill. Params=" + methodInfo2.GetParameters().Length)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch Unit.Die overload: " + ex.Message)); } } } if (num == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"No Unit.Die method was patched."); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch Unit.Die for kill reward: " + ex2.Message)); } } internal void TryRewardRandomWeaponOnEnemyDeath(object unit) { if (enableRandomWeaponOnKill == null || !enableRandomWeaponOnKill.Value || unit == null || (killRewardRequiresPlayableLevel.Value && !IsInPlayableLevel())) { return; } if (Time.unscaledTime < nextKillRewardAllowedTime) { if (logKillRewardChecks.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Kill reward skipped by cooldown."); } } else { if (!ShouldRewardForDeadUnit(unit)) { return; } int stableRuntimeUnitId = GetStableRuntimeUnitId(unit); if (stableRuntimeUnitId == 0) { return; } if (!rewardedKillUnitIds.Add(stableRuntimeUnitId)) { if (logKillRewardChecks.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Kill reward skipped: unit already rewarded. id=" + stableRuntimeUnitId)); } return; } nextKillRewardAllowedTime = Time.unscaledTime + Mathf.Max(0f, randomWeaponOnKillCooldown.Value); if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Kill reward triggered. Generating random weapon."); } ((MonoBehaviour)this).StartCoroutine(GiveRandomWeaponRoutine("enemy kill reward", currentLevelSignature)); } } private bool ShouldRewardForDeadUnit(object unit) { if (unit == null) { return false; } Component val = (Component)((unit is Component) ? unit : null); if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)val.gameObject == (Object)null) { return false; } try { GameManager instance = StaticInstance.Instance; if ((Object)(object)instance != (Object)null) { if ((Object)(object)instance.PlayerObject != (Object)null && (Object)(object)val.gameObject == (Object)(object)instance.PlayerObject) { return false; } if ((Object)(object)instance.PlayerUnit != (Object)null && unit == instance.PlayerUnit) { return false; } } } catch { } if (killRewardRequireExperienceOnKill.Value) { if (!TryReadFloatMember(unit, "ExperienceOnKill", out var value)) { if (logKillRewardChecks.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Kill reward skipped: could not read ExperienceOnKill from " + ((Object)val.gameObject).name)); } return false; } if (value <= 0f) { if (logKillRewardChecks.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Kill reward skipped: ExperienceOnKill <= 0 for " + ((Object)val.gameObject).name)); } return false; } } return true; } private bool TryReadFloatMember(object target, string memberName, out float value) { value = 0f; if (target == null) { return false; } Type type = target.GetType(); try { PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value2 = property.GetValue(target, null); if (TryConvertToFloat(value2, out value)) { return true; } } } catch { } try { FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value3 = field.GetValue(target); if (TryConvertToFloat(value3, out value)) { return true; } } } catch { } return false; } private bool TryConvertToFloat(object raw, out float value) { value = 0f; if (raw == null) { return false; } try { if (raw is float) { value = (float)raw; return true; } if (raw is int) { value = (int)raw; return true; } if (raw is double) { value = (float)(double)raw; return true; } value = Convert.ToSingle(raw); return true; } catch { return false; } } private int GetStableRuntimeUnitId(object unit) { if (unit == null) { return 0; } try { Component val = (Component)((unit is Component) ? unit : null); if ((Object)(object)val != (Object)null) { return ((Object)val).GetInstanceID(); } } catch { } try { return unit.GetHashCode(); } catch { return 0; } } private void TryPatchAmuletHelper() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("PerfectRandom.Sulfur.Gameplay.Items.AmuletHelper"); if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find AmuletHelper type."); return; } MethodInfo methodInfo = AccessTools.Method(type, "DoneChanneling", (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find AmuletHelper.DoneChanneling."); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(AmuletTeleportCleanupHook), "Prefix", (Type[])null, (Type[])null); if (methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find AmuletTeleportCleanupHook.Prefix."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched AmuletHelper.DoneChanneling."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch AmuletHelper.DoneChanneling: " + ex.Message)); } } private void TryPatchNextLevelTrigger() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("PerfectRandom.Sulfur.Core.LevelGeneration.NextLevelTrigger"); if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find NextLevelTrigger type."); return; } MethodInfo methodInfo = AccessTools.Method(type, "MakeTransition", (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find NextLevelTrigger.MakeTransition."); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(NextLevelTriggerCleanupHook), "Prefix", (Type[])null, (Type[])null); if (methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find NextLevelTriggerCleanupHook.Prefix."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched NextLevelTrigger.MakeTransition."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch NextLevelTrigger.MakeTransition: " + ex.Message)); } } private void TryPatchLevelTransitionMethods() { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(LevelTransitionCleanupHook), "Prefix", (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find LevelTransitionCleanupHook.Prefix."); return; } int num = 0; HashSet hashSet = new HashSet(); MethodInfo[] methods = typeof(GameManager).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2 == null) && IsLikelyLevelTransitionMethod(methodInfo2) && !hashSet.Contains(methodInfo2)) { try { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); hashSet.Add(methodInfo2); num++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched level transition method: GameManager." + methodInfo2.Name + "(" + methodInfo2.GetParameters().Length + " params)")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch GameManager." + methodInfo2.Name + ": " + ex.Message)); } } } if (num == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"No likely GameManager level transition methods were patched."); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Level transition cleanup patched methods: " + num)); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch level transition cleanup: " + ex2.Message)); } } private bool IsLikelyLevelTransitionMethod(MethodInfo method) { string name = method.Name; if (string.IsNullOrEmpty(name)) { return false; } switch (name) { case "GoToLevel": return true; case "GoToChurchHub": return true; case "GoToCarHub": return true; case "CompleteLevel": return true; case "SwitchLevel": return true; case "GoToNextLevel": return true; case "GoToPreviousLevel": return true; case "ReturnToChurch": return true; case "ReturnToChurchHub": return true; case "ReturnToHub": return true; case "LeaveLevel": return true; case "ExitLevel": return true; default: if (name.Contains("GoTo") && name.Contains("Level")) { return true; } if (name.Contains("Switch") && name.Contains("Level")) { return true; } if (name.Contains("Load") && name.Contains("Level")) { return true; } if (name.Contains("Next") && name.Contains("Level")) { return true; } if (name.Contains("Return") && (name.Contains("Church") || name.Contains("Hub"))) { return true; } return false; } } private void Update() { if (enableMod.Value) { HandleDebugKey(); HandleLevelSignatureAutoGive(); } } internal bool ShouldCleanupBeforeLevelTransition() { return cleanupGeneratedWeaponsBeforeLevelTransition != null && cleanupGeneratedWeaponsBeforeLevelTransition.Value; } internal bool ShouldDestroyGeneratedWeaponsOnDrop() { return destroyGeneratedWeaponsOnDrop != null && destroyGeneratedWeaponsOnDrop.Value; } internal static bool IsGeneratedWeapon(InventoryItem item) { if ((Object)(object)item == (Object)null) { return false; } try { return (Object)(object)((Component)item).GetComponent() != (Object)null; } catch { return false; } } internal static void RemoveGeneratedWeaponSafely(InventoryItem item, string reason) { if ((Object)(object)item == (Object)null) { return; } try { item.GetRemovedByExternalFactor(reason); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Failed to remove generated weapon: " + ex.Message)); } } } private void HandleDebugKey() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (!debugKeyEnabled.Value) { return; } Keyboard current = Keyboard.current; if (current == null) { return; } Key value = debugKey.Value; if ((int)value == 0) { return; } try { if (((ButtonControl)current[value]).wasPressedThisFrame) { ((MonoBehaviour)this).StartCoroutine(GiveRandomWeaponRoutine("debug key " + ((object)(Key)(ref value)).ToString(), 0)); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to read debug key " + ((object)(Key)(ref value)).ToString() + ": " + ex.Message)); } } private void HandleLevelSignatureAutoGive() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Invalid comparison between Unknown and I4 if (!randomizeOnLevelStart.Value) { return; } GameManager instance; try { instance = StaticInstance.Instance; } catch { return; } if ((Object)(object)instance == (Object)null) { return; } if (instance.InSafeZone) { ResetAutoGiveMemoryForSafeZone(); } else if ((int)instance.gameState == 1 || (int)instance.gameState == 0) { sawLoadingOrLevelTransition = true; currentLevelSignature = 0; cachedLevelSignature = 0; nextSignatureCheckTime = 0f; } else { if ((int)instance.gameState != 3 || !IsInPlayableLevel()) { return; } int num = GetCachedLevelSignature(); if (num != 0) { if (currentLevelSignature == 0) { currentLevelSignature = num; } bool flag = sawLoadingOrLevelTransition && currentLevelSignature != num; bool flag2 = sawLoadingOrLevelTransition && currentLevelSignature == num; if (flag || flag2) { currentLevelSignature = num; sawLoadingOrLevelTransition = false; TryStartAutoGiveForSignature(num, "level signature"); } } } } private void ResetAutoGiveMemoryForSafeZone() { sawLoadingOrLevelTransition = true; currentLevelSignature = 0; cachedLevelSignature = 0; nextSignatureCheckTime = 0f; rewardedKillUnitIds.Clear(); nextKillRewardAllowedTime = 0f; autoGivenLevelSignatures.Clear(); } private void TryStartAutoGiveForSignature(int signature, string reason) { if (signature != 0 && !autoGiveRoutineRunning && !autoGivenLevelSignatures.Contains(signature)) { autoGivenLevelSignatures.Add(signature); ((MonoBehaviour)this).StartCoroutine(AutoGiveForLevelSignature(signature, reason)); } } [IteratorStateMachine(typeof(d__78))] private IEnumerator AutoGiveForLevelSignature(int signature, string reason) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__78(0) { <>4__this = this, signature = signature, reason = reason }; } private bool IsInPlayableLevel() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 try { GameManager instance = StaticInstance.Instance; if ((Object)(object)instance == (Object)null) { return false; } if ((int)instance.gameState != 3) { return false; } if (instance.InSafeZone) { return false; } if ((Object)(object)instance.PlayerUnit == (Object)null) { return false; } if ((Object)(object)StaticInstance.Instance == (Object)null) { return false; } if ((Object)(object)StaticInstance.Instance.PlayerBackpackGrid == (Object)null) { return false; } if ((Object)(object)StaticInstance.Instance.InventoryUI == (Object)null) { return false; } return true; } catch { return false; } } private int GetCachedLevelSignature() { float num = Mathf.Clamp(sceneSignatureCheckInterval.Value, 0.1f, 5f); if (cachedLevelSignature != 0 && Time.unscaledTime < nextSignatureCheckTime) { return cachedLevelSignature; } cachedLevelSignature = ComputeLevelSignature(); nextSignatureCheckTime = Time.unscaledTime + num; return cachedLevelSignature; } private int ComputeLevelSignature() { //IL_0043: 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) try { int num = 17; GameManager instance = StaticInstance.Instance; if ((Object)(object)instance != (Object)null) { num = num * 31 + instance.InSafeZone.GetHashCode(); } num = num * 31 + SceneManager.sceneCount; for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); if (!((Scene)(ref sceneAt)).IsValid() || !((Scene)(ref sceneAt)).isLoaded) { continue; } num = num * 31 + ((Scene)(ref sceneAt)).name.GetHashCode(); GameObject[] rootGameObjects = ((Scene)(ref sceneAt)).GetRootGameObjects(); num = num * 31 + rootGameObjects.Length; foreach (GameObject val in rootGameObjects) { if (!((Object)(object)val == (Object)null)) { num = num * 31 + ((Object)val).name.GetHashCode(); num = num * 31 + val.activeSelf.GetHashCode(); } } } return num; } catch { return 0; } } [IteratorStateMachine(typeof(d__82))] private IEnumerator GiveRandomWeaponRoutine(string reason, int levelSignature) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__82(0) { <>4__this = this, reason = reason, levelSignature = levelSignature }; } private InventorySlot PrepareTargetWeaponSlot() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_004c: Unknown result type (might be due to invalid IL or missing references) List preferredWeaponSlotOrder = GetPreferredWeaponSlotOrder(); foreach (InventorySlot item in preferredWeaponSlotOrder) { if (TryPrepareWeaponSlot(item)) { return item; } } return (InventorySlot)9; } private List GetPreferredWeaponSlotOrder() { List list = new List(); switch (preferredWeaponSlot.Value) { case PreferredWeaponSlotMode.Weapon0: list.Add((InventorySlot)4); list.Add((InventorySlot)5); return list; case PreferredWeaponSlotMode.Weapon1: list.Add((InventorySlot)5); list.Add((InventorySlot)4); return list; case PreferredWeaponSlotMode.Random: if (Random.value < 0.5f) { list.Add((InventorySlot)4); list.Add((InventorySlot)5); } else { list.Add((InventorySlot)5); list.Add((InventorySlot)4); } return list; default: list.Add((InventorySlot)4); list.Add((InventorySlot)5); return list; } } private bool TryPrepareWeaponSlot(InventorySlot slot) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) PaperdollSlot paperdollSlot = GetPaperdollSlot(slot); if ((Object)(object)paperdollSlot == (Object)null) { return false; } InventoryItem itemInSlot = paperdollSlot.itemInSlot; if ((Object)(object)itemInSlot == (Object)null) { return true; } if ((Object)(object)((Component)itemInSlot).GetComponent() != (Object)null) { try { itemInSlot.GetRemovedByExternalFactor("Random Weapon Per Level replacing generated weapon"); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to remove old generated weapon from " + ((object)(InventorySlot)(ref slot)).ToString() + ": " + ex.Message)); return false; } } if (!CanMoveItemToBackpack(itemInSlot)) { if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Cannot move existing weapon to backpack, skipping slot " + ((object)(InventorySlot)(ref slot)).ToString() + ": " + itemInSlot.itemDefinition.displayName)); } return false; } try { itemInSlot.TryMoveToPlayerInventory(); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to move existing weapon to backpack from " + ((object)(InventorySlot)(ref slot)).ToString() + ": " + ex2.Message)); return false; } return true; } private bool IsWeaponSlotEmpty(InventorySlot slot) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) InventoryItem itemInWeaponSlot = GetItemInWeaponSlot(slot); return (Object)(object)itemInWeaponSlot == (Object)null; } private InventoryItem GetItemInWeaponSlot(InventorySlot slot) { //IL_0003: 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_0053: Unknown result type (might be due to invalid IL or missing references) try { PaperdollSlot paperdollSlot = GetPaperdollSlot(slot); if ((Object)(object)paperdollSlot != (Object)null) { return paperdollSlot.itemInSlot; } } catch { } try { EquipmentManager equipmentManager = GetEquipmentManager(); if ((Object)(object)equipmentManager != (Object)null && equipmentManager.EquippedItems.ContainsKey(slot)) { return equipmentManager.EquippedItems[slot]; } } catch { } return null; } private PaperdollSlot GetPaperdollSlot(InventorySlot slot) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) try { UIManager instance = StaticInstance.Instance; if ((Object)(object)instance == (Object)null) { return null; } if ((Object)(object)instance.Paperdoll == (Object)null) { return null; } return instance.Paperdoll.GetSlot(slot); } catch { return null; } } private bool CanMoveItemToBackpack(InventoryItem item) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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) if ((Object)(object)item == (Object)null) { return false; } try { ItemGrid playerBackpackGrid = GetPlayerBackpackGrid(); if ((Object)(object)playerBackpackGrid == (Object)null) { return false; } Vector2Int inventorySize = item.InventorySize; Vector2Int possibleSpace = playerBackpackGrid.GetPossibleSpace(inventorySize, false, true); if (((Vector2Int)(ref possibleSpace)).x >= 0 && ((Vector2Int)(ref possibleSpace)).y >= 0) { return true; } Vector2Int val = default(Vector2Int); ((Vector2Int)(ref val))..ctor(((Vector2Int)(ref inventorySize)).y, ((Vector2Int)(ref inventorySize)).x); Vector2Int possibleSpace2 = playerBackpackGrid.GetPossibleSpace(val, false, true); return ((Vector2Int)(ref possibleSpace2)).x >= 0 && ((Vector2Int)(ref possibleSpace2)).y >= 0; } catch { return false; } } private void MarkGeneratedWeapon(InventoryItem item, string reason, int levelSignature) { if (!((Object)(object)item == (Object)null)) { RandomWeaponMarker randomWeaponMarker = ((Component)item).GetComponent(); if ((Object)(object)randomWeaponMarker == (Object)null) { randomWeaponMarker = ((Component)item).gameObject.AddComponent(); } generationCounter++; randomWeaponMarker.generationId = generationCounter; randomWeaponMarker.levelSignature = levelSignature; randomWeaponMarker.reason = reason; randomWeaponMarker.weaponName = (((Object)(object)item.itemDefinition != (Object)null) ? item.itemDefinition.displayName : "Unknown"); } } internal int CleanupOldGeneratedWeapons(InventoryItem keepItem) { int num = 0; try { RandomWeaponMarker[] array = Resources.FindObjectsOfTypeAll(); RandomWeaponMarker[] array2 = array; foreach (RandomWeaponMarker randomWeaponMarker in array2) { if ((Object)(object)randomWeaponMarker == (Object)null) { continue; } InventoryItem component = ((Component)randomWeaponMarker).GetComponent(); if (!((Object)(object)component == (Object)null) && (!((Object)(object)keepItem != (Object)null) || !((Object)(object)component == (Object)(object)keepItem))) { try { component.GetRemovedByExternalFactor("Random Weapon Per Level cleanup"); num++; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to remove generated weapon: " + ex.Message)); } } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to cleanup generated weapons: " + ex2.Message)); } return num; } private void TrySelectWeaponSlot(InventorySlot slot) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) try { EquipmentManager equipmentManager = GetEquipmentManager(); if (!((Object)(object)equipmentManager == (Object)null)) { equipmentManager.ChangeWeapon(slot, true); } } catch (Exception ex) { if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to select generated weapon slot " + ((object)(InventorySlot)(ref slot)).ToString() + ": " + ex.Message)); } } } private ItemGrid GetPlayerBackpackGrid() { try { UIManager instance = StaticInstance.Instance; if ((Object)(object)instance == (Object)null) { return null; } return instance.PlayerBackpackGrid; } catch { return null; } } private HashSet CapturePlayerInventoryItems() { HashSet hashSet = new HashSet(); try { ItemGrid playerBackpackGrid = GetPlayerBackpackGrid(); if ((Object)(object)playerBackpackGrid != (Object)null) { foreach (InventoryItem item in playerBackpackGrid.AllItems()) { if ((Object)(object)item != (Object)null) { hashSet.Add(item); } } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to capture backpack items: " + ex.Message)); } try { EquipmentManager equipmentManager = GetEquipmentManager(); if ((Object)(object)equipmentManager != (Object)null) { foreach (InventoryItem value in equipmentManager.EquippedItems.Values) { if ((Object)(object)value != (Object)null) { hashSet.Add(value); } } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to capture equipped items: " + ex2.Message)); } return hashSet; } private List GetAllPlayerItemsSnapshot() { HashSet collection = CapturePlayerInventoryItems(); return new List(collection); } private InventoryItem FindNewInventoryItem(HashSet beforeItems, WeaponSO weapon) { if ((Object)(object)weapon == (Object)null) { return null; } List allPlayerItemsSnapshot = GetAllPlayerItemsSnapshot(); foreach (InventoryItem item in allPlayerItemsSnapshot) { if ((Object)(object)item == (Object)null || (beforeItems != null && beforeItems.Contains(item)) || !((Object)(object)item.itemDefinition == (Object)(object)weapon)) { continue; } return item; } return null; } private EquipmentManager GetEquipmentManager() { try { GameManager instance = StaticInstance.Instance; if ((Object)(object)instance == (Object)null) { return null; } if ((Object)(object)instance.EquipmentManager != (Object)null) { return instance.EquipmentManager; } if ((Object)(object)instance.PlayerScript != (Object)null) { return instance.PlayerScript.equipmentManager; } return null; } catch { return null; } } private int ApplyRandomOilsIfNeeded(InventoryItem item) { //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) if (!enableRandomOils.Value) { return 0; } if ((Object)(object)item == (Object)null) { return 0; } ItemDefinition itemDefinition = item.itemDefinition; WeaponSO val = (WeaponSO)(object)((itemDefinition is WeaponSO) ? itemDefinition : null); if ((Object)(object)val == (Object)null) { return 0; } if (!val.TypeIsEnchantable) { return 0; } int num = Mathf.Clamp(minOilCount.Value, 1, 5); int max = Mathf.Clamp(maxOilCount.Value, num, 5); int num2 = PickWeightedOilCount(num, max); LootTable oilLootTable = GetOilLootTable(); if ((Object)(object)oilLootTable == (Object)null || oilLootTable.entries == null || oilLootTable.entries.Count == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not apply random oils: oil loot table is empty."); return 0; } HashSet hashSet = new HashSet(); int num3 = 0; int num4 = 0; int num5 = num2 * 30; while (num3 < num2 && num4 < num5) { num4++; ItemDefinition val2 = null; try { val2 = oilLootTable.SelectOneItem(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to select random oil: " + ex.Message)); break; } if ((Object)(object)val2 == (Object)null || !((EnchantmentId)(ref val2.appliesEnchantment)).IsValid || hashSet.Contains(val2.id) || IsEnchantmentAlreadyApplied(item, val2) || (respectEnchantmentSlots.Value && !item.IsEnchantmentCompatible(val2))) { continue; } try { item.AddEnchantment(val2, false); hashSet.Add(val2.id); num3++; if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied random oil to " + item.itemDefinition.displayName + ": " + val2.displayName)); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to apply random oil " + val2.displayName + " to " + item.itemDefinition.displayName + ": " + ex2.Message)); } } return num3; } private int PickWeightedOilCount(int min, int max) { min = Mathf.Clamp(min, 1, 5); max = Mathf.Clamp(max, min, 5); float num = 0f; for (int i = min; i <= max; i++) { num += GetOilCountWeight(i); } if (num <= 0f) { return Random.Range(min, max + 1); } float num2 = Random.value * num; float num3 = 0f; for (int j = min; j <= max; j++) { num3 += GetOilCountWeight(j); if (num2 <= num3) { return j; } } return max; } private float GetOilCountWeight(int count) { return count switch { 1 => 5f, 2 => 4f, 3 => 3.5f, 4 => 3f, 5 => 2.5f, _ => 1f, }; } private int ApplyRandomScrollsIfNeeded(InventoryItem item) { //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) if (!enableRandomScrolls.Value) { return 0; } if ((Object)(object)item == (Object)null) { return 0; } ItemDefinition itemDefinition = item.itemDefinition; WeaponSO val = (WeaponSO)(object)((itemDefinition is WeaponSO) ? itemDefinition : null); if ((Object)(object)val == (Object)null) { return 0; } if (!val.TypeIsEnchantable) { return 0; } float num = Mathf.Clamp01(scrollChance.Value); if (Random.value > num) { if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Random scroll roll skipped for " + item.itemDefinition.displayName + ".")); } return 0; } LootTable scrollLootTable = GetScrollLootTable(); if ((Object)(object)scrollLootTable == (Object)null || scrollLootTable.entries == null || scrollLootTable.entries.Count == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not apply random scrolls: scroll loot table is empty."); return 0; } int num2 = Mathf.Clamp(minScrollCount.Value, 1, 5); int num3 = Mathf.Clamp(maxScrollCount.Value, num2, 5); int num4 = Random.Range(num2, num3 + 1); HashSet hashSet = new HashSet(); int num5 = 0; int num6 = 0; int num7 = num4 * 30; while (num5 < num4 && num6 < num7) { num6++; ItemDefinition val2 = null; try { val2 = scrollLootTable.SelectOneItem(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to select random scroll: " + ex.Message)); break; } if ((Object)(object)val2 == (Object)null || !((EnchantmentId)(ref val2.appliesEnchantment)).IsValid || hashSet.Contains(val2.id) || IsEnchantmentAlreadyApplied(item, val2) || (respectEnchantmentSlots.Value && !item.IsEnchantmentCompatible(val2))) { continue; } try { item.AddEnchantment(val2, false); hashSet.Add(val2.id); num5++; if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied random scroll to " + item.itemDefinition.displayName + ": " + val2.displayName)); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to apply random scroll " + val2.displayName + " to " + item.itemDefinition.displayName + ": " + ex2.Message)); } } return num5; } private bool IsEnchantmentAlreadyApplied(InventoryItem item, ItemDefinition enchantmentItem) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null || (Object)(object)enchantmentItem == (Object)null) { return false; } if (!((EnchantmentId)(ref enchantmentItem.appliesEnchantment)).IsValid) { return false; } try { EnchantmentDefinition asset = AssetAccess.GetAsset(enchantmentItem.appliesEnchantment); if ((Object)(object)asset == (Object)null) { return false; } return item.enchantments != null && item.enchantments.Contains(asset); } catch { return false; } } private int ApplyRandomAttachmentsIfNeeded(InventoryItem item) { //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) if (!enableRandomAttachments.Value) { return 0; } if ((Object)(object)item == (Object)null) { return 0; } ItemDefinition itemDefinition = item.itemDefinition; WeaponSO val = (WeaponSO)(object)((itemDefinition is WeaponSO) ? itemDefinition : null); if ((Object)(object)val == (Object)null) { return 0; } float num = Mathf.Clamp01(attachmentChance.Value); if (Random.value > num) { if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Random attachment roll skipped for " + item.itemDefinition.displayName + ".")); } return 0; } LootTable attachmentLootTable = GetAttachmentLootTable(); if ((Object)(object)attachmentLootTable == (Object)null || attachmentLootTable.entries == null || attachmentLootTable.entries.Count == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not apply random attachments: attachment loot table is empty."); return 0; } int num2 = Mathf.Clamp(minAttachmentCount.Value, 1, 4); int num3 = Mathf.Clamp(maxAttachmentCount.Value, num2, 4); int num4 = Random.Range(num2, num3 + 1); HashSet hashSet = new HashSet(); int num5 = 0; while (num5 < num4) { List list = BuildCompatibleAttachmentCandidates(item, attachmentLootTable, hashSet); if (list.Count == 0) { if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("No more compatible attachments for " + item.itemDefinition.displayName + ". Applied " + num5 + "/" + num4 + ".")); } break; } ItemDefinition val2 = PickWeightedAttachment(list); if ((Object)(object)val2 == (Object)null) { break; } try { item.AddAttachment(val2, false); hashSet.Add(val2.id); num5++; if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied random attachment to " + item.itemDefinition.displayName + ": " + val2.displayName)); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to apply random attachment " + val2.displayName + " to " + item.itemDefinition.displayName + ": " + ex.Message)); hashSet.Add(val2.id); } } return num5; } private List BuildCompatibleAttachmentCandidates(InventoryItem item, LootTable attachmentTable, HashSet usedAttachmentIds) { //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if ((Object)(object)item == (Object)null) { return list; } if ((Object)(object)attachmentTable == (Object)null || attachmentTable.entries == null) { return list; } foreach (LootEntry entry in attachmentTable.entries) { ItemDefinition lootItem = entry.lootItem; if ((Object)(object)lootItem == (Object)null || entry.lootWeight <= 0f || (usedAttachmentIds != null && usedAttachmentIds.Contains(lootItem.id))) { continue; } bool flag = false; try { flag = item.IsAttachmentCompatible(lootItem); } catch (Exception ex) { if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Attachment compatibility check failed for " + lootItem.displayName + " on " + item.itemDefinition.displayName + ": " + ex.Message)); } flag = false; } if (flag) { list.Add(new WeightedAttachmentCandidate(lootItem, entry.lootWeight)); } } return list; } private ItemDefinition PickWeightedAttachment(List candidates) { if (candidates == null || candidates.Count == 0) { return null; } float num = 0f; for (int i = 0; i < candidates.Count; i++) { num += Mathf.Max(0f, candidates[i].Weight); } if (num <= 0f) { int index = Random.Range(0, candidates.Count); return candidates[index].Item; } float num2 = Random.value * num; float num3 = 0f; for (int j = 0; j < candidates.Count; j++) { num3 += Mathf.Max(0f, candidates[j].Weight); if (num2 <= num3) { return candidates[j].Item; } } return candidates[candidates.Count - 1].Item; } private void GrantMinimumRankForAppliedEnchantments(InventoryItem item, int appliedEnchantmentCount) { if (!grantRankForAppliedOils.Value || (Object)(object)item == (Object)null || appliedEnchantmentCount <= 0) { return; } int num = Mathf.Clamp(appliedEnchantmentCount, 0, 5); if (num <= 0) { return; } try { float experience = item.GetExperience(); float minimumExperienceForRank = GetMinimumExperienceForRank(num); if (!(experience >= minimumExperienceForRank)) { item.AddExperience(minimumExperienceForRank - experience); if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Raised rank for " + item.itemDefinition.displayName + " to match applied enchantments. Target rank: " + num)); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to raise weapon rank for applied enchantments: " + ex.Message)); } } private float GetMinimumExperienceForRank(int rank) { return rank switch { 1 => 50f, 2 => 125f, 3 => 312.5f, 4 => 781.25f, 5 => 1953.125f, _ => 0f, }; } private LootTable GetOilLootTable() { try { GameManager instance = StaticInstance.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.Settings == (Object)null || (Object)(object)instance.Settings.LootSettings == (Object)null) { return null; } return instance.Settings.LootSettings.enchantmentOilLootTable; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to get oil loot table: " + ex.Message)); return null; } } private LootTable GetScrollLootTable() { try { GameManager instance = StaticInstance.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.Settings == (Object)null || (Object)(object)instance.Settings.LootSettings == (Object)null) { return null; } return instance.Settings.LootSettings.enchantmentLootTable; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to get scroll loot table: " + ex.Message)); return null; } } private LootTable GetAttachmentLootTable() { try { GameManager instance = StaticInstance.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.Settings == (Object)null || (Object)(object)instance.Settings.LootSettings == (Object)null) { return null; } return instance.Settings.LootSettings.attachmentLootTable; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to get attachment loot table: " + ex.Message)); return null; } } private void NormalizeDurabilityIfNeeded(InventoryItem item) { if ((Object)(object)item == (Object)null) { return; } try { if (!item.HasDurability) { return; } int durabilityMax = item.DurabilityMax; int durabilityCurrent = item.DurabilityCurrent; if (durabilityCurrent > durabilityMax) { item.ModifyDurability((float)(durabilityMax - durabilityCurrent)); if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Clamped durability for " + item.itemDefinition.displayName + " to max durability: " + durabilityMax)); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to normalize durability: " + ex.Message)); } } private void FixDurabilityIfNeeded(InventoryItem item) { if (!fixLowDurability.Value || (Object)(object)item == (Object)null) { return; } try { if (!item.HasDurability) { return; } float num = Mathf.Clamp01(minimumDurabilityNormalized.Value); if (item.DurabilityNormalized >= num) { return; } int durabilityMax = item.DurabilityMax; int num2 = Mathf.CeilToInt((float)durabilityMax * num); int num3 = num2 - item.DurabilityCurrent; if (num3 > 0) { item.ModifyDurability((float)num3); if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Raised durability for " + item.itemDefinition.displayName + " to at least " + Mathf.RoundToInt(num * 100f) + "%")); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to fix generated weapon durability: " + ex.Message)); } } private void TrySyncInstancedWeapon(InventoryItem item) { if ((Object)(object)item == (Object)null) { return; } try { item.SyncWithInstancedVersion(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to sync generated weapon instance: " + ex.Message)); } } private WeaponSO PickRandomWeapon() { EnsureWeaponPool(); if (cachedWeaponPool.Count == 0) { return null; } int index = Random.Range(0, cachedWeaponPool.Count); return cachedWeaponPool[index]; } private void EnsureWeaponPool() { if (cachedWeaponPool.Count <= 0) { RefreshWeaponPool(); } } private void RefreshWeaponPool() { cachedWeaponPool.Clear(); WeaponSO[] array; try { array = Resources.FindObjectsOfTypeAll(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to find WeaponSO assets: " + ex.Message)); return; } WeaponSO[] array2 = array; foreach (WeaponSO val in array2) { if (IsValidWeaponForRandomPool(val) && !cachedWeaponPool.Contains(val)) { cachedWeaponPool.Add(val); } } cachedWeaponPool.Sort((WeaponSO a, WeaponSO b) => string.Compare(GetWeaponName(a), GetWeaponName(b), StringComparison.OrdinalIgnoreCase)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Random weapon pool loaded. Valid weapons: " + cachedWeaponPool.Count)); if (!logWeaponPool.Value) { return; } foreach (WeaponSO item in cachedWeaponPool) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Random pool weapon: " + GetWeaponName(item))); } } private bool IsValidWeaponForRandomPool(WeaponSO weapon) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Invalid comparison between Unknown and I4 //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Invalid comparison between Unknown and I4 //IL_010c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)weapon == (Object)null) { return false; } if (requireUsableByPlayer.Value && !weapon.usableByPlayer) { return false; } if (gunsOnly.Value) { if (weapon.IsMelee) { return false; } if (weapon.IsThrowable) { return false; } } if (excludeStartsEmpty.Value && weapon.startsEmpty) { return false; } if (requireAmmoMagazine.Value && weapon.iAmmoMax <= 0) { return false; } if (requireWeaponPrefab.Value && (Object)(object)((ItemDefinition)weapon).prefab == (Object)null) { return false; } if ((int)((ItemDefinition)weapon).slotType != 7) { return false; } if ((int)weapon.caliber == 0) { return false; } if ((int)weapon.projectileType == 0 && !((Object)(object)weapon.customProjectile != (Object)null)) { return false; } if (string.IsNullOrWhiteSpace(((ItemDefinition)weapon).displayName)) { return false; } return true; } private string BuildCreatedItemInfo(InventoryItem item) { if ((Object)(object)item == (Object)null) { return "null"; } int num = 0; try { num = ((item.enchantments != null) ? item.enchantments.Count : 0); } catch { num = -1; } int num2 = 0; try { num2 = ((item.attachments != null) ? item.attachments.Count : 0); } catch { num2 = -1; } string text = "rank="; try { text += item.GetRankLevel(); } catch { text += "unknown"; } string text2 = "durability="; try { text2 = ((!item.HasDurability) ? (text2 + "none") : (text2 + item.DurabilityCurrent + "/" + item.DurabilityMax)); } catch { text2 += "unknown"; } string text3 = "marker="; try { RandomWeaponMarker component = ((Component)item).GetComponent(); text3 += (((Object)(object)component != (Object)null) ? component.generationId.ToString() : "none"); } catch { text3 += "unknown"; } return "created item found, enchantments=" + num + ", attachments=" + num2 + ", " + text + ", " + text2 + ", " + text3; } private static string GetWeaponName(WeaponSO weapon) { if ((Object)(object)weapon == (Object)null) { return "null"; } if (!string.IsNullOrWhiteSpace(((ItemDefinition)weapon).displayName)) { return ((ItemDefinition)weapon).displayName; } return ((Object)weapon).name; } } internal static class AmuletTeleportCleanupHook { public static void Prefix() { try { if (!((Object)(object)Plugin.Instance == (Object)null)) { Plugin.Instance.CleanupGeneratedWeaponsForTransition("AmuletHelper.DoneChanneling"); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Failed to cleanup generated weapons in AmuletHelper.DoneChanneling: " + ex.Message)); } } } } internal static class NextLevelTriggerCleanupHook { public static void Prefix() { try { if (!((Object)(object)Plugin.Instance == (Object)null)) { Plugin.Instance.CleanupGeneratedWeaponsForTransition("NextLevelTrigger.MakeTransition"); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Failed to cleanup generated weapons in NextLevelTrigger.MakeTransition: " + ex.Message)); } } } } internal static class GeneratedWeaponDropFromPlayerHook { public static bool Prefix(InventoryItem __instance) { if ((Object)(object)Plugin.Instance == (Object)null) { return true; } if (!Plugin.Instance.ShouldDestroyGeneratedWeaponsOnDrop()) { return true; } if (!Plugin.IsGeneratedWeapon(__instance)) { return true; } Plugin.RemoveGeneratedWeaponSafely(__instance, "Random Weapon Per Level: generated weapon dropped"); return false; } } internal static class UnitDieRandomWeaponRewardHook { public static void Prefix(object __instance) { try { if (!((Object)(object)Plugin.Instance == (Object)null)) { Plugin.Instance.TryRewardRandomWeaponOnEnemyDeath(__instance); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Failed to process random weapon kill reward: " + ex.Message)); } } } } internal static class LevelTransitionCleanupHook { public static void Prefix(MethodBase __originalMethod) { try { if (!((Object)(object)Plugin.Instance == (Object)null)) { string reason = ((__originalMethod != null) ? (__originalMethod.DeclaringType.Name + "." + __originalMethod.Name) : "unknown transition method"); Plugin.Instance.CleanupGeneratedWeaponsForTransition(reason); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Failed to cleanup generated weapons before transition: " + ex.Message)); } } } }