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 HarmonyLib; using UnityEngine; 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("BoneLordItems")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BoneLordItems")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("cf5606d8-438e-4729-947c-e892ebfe446e")] [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 BoneLordItems; [BepInPlugin("com.yourname.bonelorditems", "Bone Lord Items", "1.5.20")] public class Plugin : BaseUnityPlugin { private static bool injected = false; private static int attempts = 0; private static float nextTryAt = 0f; private const float RetryInterval = 1f; private const int MaxAttempts = 300; private const string ID_SOUL_ECHO = "20832306"; private const string ID_NEOPHYTE = "29042550"; private const string ID_FLUORITE = "57247840"; private const string ID_PLAIN = "14265295"; private const string HYDRATED_ID = "20309875"; private const string ID_CELESTIAL_SMITE = "11565860"; private const string ID_PAGE1 = "11021645"; private const string ID_PAGE2 = "271648"; private const string ORIGINAL_CAPTAIN = "A Skeleton Captain"; private const string FABLED_CAPTAIN = "Fabled Skeletal Captain"; private const string ORIGINAL_LAZALITH = "Lazalith, Soldier of Sivakaya"; private const string FABLED_LAZALITH = "Fabled Lazalith, Demon of Sivakaya"; private const string ORIGINAL_PEON = "Peon"; private const string FABLED_PEON = "The Fabled Crimson Peon"; private const string ORIGINAL_GUARD = "Spectral King's Guard"; private const string FABLED_GUARD = "Fabled Spectral King's Guard"; private const float FABLED_CHANCE = 0.15f; private const float GUARD_FABLED_CHANCE = 0.5f; private const float STAT_MULTIPLIER = 1.5f; private const int LEVEL_BONUS = 4; private const int FORCED_HP = 3048; private const int PEON_HP = 30000; private const float TARGET_SCALE = 1.8f; private const float PEON_SCALE = 2.5f; private const float LAZALITH_SCALE = 4f; private const int LAZALITH_LEVEL = 25; private const int PEON_LEVEL = 28; private const int GUARD_LEVEL = 23; private const float PEON_RESPAWN_SECONDS = 600f; private const float FABLED_MSG_INTERVAL = 180f; private const float WORLD_SCAN_INTERVAL = 2f; private static object cloneSkeleton; private static object cloneKnight; private static object cloneHero; private static object cloneTorment; private static object talismanItemRef; private static object visageItemRef; private static object amuletItemRef; private static object sigilItemRef; private static object celestialSmiteRef; private static object page1Ref; private static object page2Ref; private static readonly HashSet processedCaptains = new HashSet(); private static readonly HashSet processedLazalith = new HashSet(); private static readonly HashSet processedGuards = new HashSet(); private static bool fireFxSpawned = false; private static float nextFireTry = 0f; private static int fireFxFailLogs = 0; private static string lastScene = ""; private static bool bonepitsMessageShown = false; private static bool braxMessageShown = false; private static float nextPeonSpawnAt = 0f; private static float nextWorldScanAt = 0f; private static float nextCaptainMsgAt = 0f; private static float nextLazalithMsgAt = 0f; private static float nextPeonMsgAt = 0f; private static float nextGuardMsgAt = 0f; private static GameObject cachedFabledCaptain; private static GameObject cachedFabledLazalith; private static GameObject cachedFabledPeon; private static GameObject cachedFabledGuard; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) new Harmony("com.yourname.bonelorditems").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Bone Lord Items 1.5.20 – share build (no Reaper override; Guard 50%)"); nextTryAt = Time.unscaledTime + 3f; } private void Update() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string text = ((Scene)(ref activeScene)).name ?? ""; if (text != lastScene) { lastScene = text; bonepitsMessageShown = false; braxMessageShown = false; fireFxSpawned = false; nextFireTry = 0f; fireFxFailLogs = 0; nextPeonSpawnAt = 0f; nextCaptainMsgAt = 0f; nextLazalithMsgAt = 0f; nextPeonMsgAt = 0f; nextGuardMsgAt = 0f; nextWorldScanAt = 0f; processedCaptains.Clear(); processedLazalith.Clear(); processedGuards.Clear(); cachedFabledCaptain = null; cachedFabledLazalith = null; cachedFabledPeon = null; cachedFabledGuard = null; } bool flag = text.IndexOf("Bonepit", StringComparison.OrdinalIgnoreCase) >= 0; bool flag2 = text.IndexOf("Braxonian", StringComparison.OrdinalIgnoreCase) >= 0; bool flag3 = text.IndexOf("Undercity", StringComparison.OrdinalIgnoreCase) >= 0; bool flag4 = text.IndexOf("SaltedStrand", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Salted Strand", StringComparison.OrdinalIgnoreCase) >= 0; if (!bonepitsMessageShown && flag) { bonepitsMessageShown = true; ShowBonepitsSenseMessage(); } if (flag2) { if (!braxMessageShown) { braxMessageShown = true; SendYellow("*** THE OBELISK IN BRAXONIAN DESERT EMITS A CRIMSON AURA, DISCOURAGING ALL BUT THE MOST HARDY ADVENTURERS ***"); } if (!fireFxSpawned && Time.time >= nextFireTry) { nextFireTry = Time.time + 5f; if (TrySpawnFireFx()) { fireFxSpawned = true; Debug.Log((object)"[BoneLordItems] ★ FX_Fire_01 (20,1,20) + FX_Fire_Embers_01 (10,10,10) spawned"); } else if (fireFxFailLogs < 3) { fireFxFailLogs++; Debug.Log((object)("[BoneLordItems] Fire FX not in memory yet – retry " + fireFxFailLogs + "/3")); } } ProcessCrimsonPeon(); } ProcessFabledMessageTimersCached(); if (!injected && Time.unscaledTime >= nextTryAt) { nextTryAt = Time.unscaledTime + 1f; if (LooksLikeGameDataPresent()) { attempts++; if (attempts > 300) { if (attempts == 301) { ((BaseUnityPlugin)this).Logger.LogError((object)("[BoneLordItems] Gave up after " + 300 + " attempts.")); } } else { try { int num = InjectEverything(); if (num > 0) { injected = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[BoneLordItems] === SUCCESS – " + num + " objects ===")); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[BoneLordItems] " + ex)); } } } } if (Time.time >= nextWorldScanAt) { nextWorldScanAt = Time.time + 2f; if (flag || flag2 || flag3 || flag4) { RunCombinedWorldScan(flag, flag2, flag3, flag4); } } } private static void RunCombinedWorldScan(bool inBonepits, bool inBrax, bool inUndercity, bool inSaltedStrand) { //IL_00d9: 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) if ((Object)(object)cachedFabledCaptain != (Object)null && !Object.op_Implicit((Object)(object)cachedFabledCaptain)) { cachedFabledCaptain = null; } if ((Object)(object)cachedFabledLazalith != (Object)null && !Object.op_Implicit((Object)(object)cachedFabledLazalith)) { cachedFabledLazalith = null; } if ((Object)(object)cachedFabledPeon != (Object)null && !Object.op_Implicit((Object)(object)cachedFabledPeon)) { cachedFabledPeon = null; } if ((Object)(object)cachedFabledGuard != (Object)null && !Object.op_Implicit((Object)(object)cachedFabledGuard)) { cachedFabledGuard = null; } GameObject[] array = Resources.FindObjectsOfTypeAll(); foreach (GameObject val in array) { if ((Object)(object)val == (Object)null || !val.activeInHierarchy) { continue; } Scene scene = val.scene; if (!string.IsNullOrEmpty(((Scene)(ref scene)).name)) { string name = ((Object)val).name; if (inBonepits && (name == "A Skeleton Captain" || name == "Fabled Skeletal Captain")) { HandleCaptain(val); } else if (inSaltedStrand && (name == "Lazalith, Soldier of Sivakaya" || name == "Fabled Lazalith, Demon of Sivakaya")) { HandleLazalith(val); } else if (inBrax && name == "The Fabled Crimson Peon") { cachedFabledPeon = val; } else if (inUndercity && name.IndexOf("Spectral King's Guard", StringComparison.OrdinalIgnoreCase) >= 0) { HandleGuard(val); } } } } private static void HandleCaptain(GameObject go) { int instanceID = ((Object)go).GetInstanceID(); if (processedCaptains.Contains(instanceID)) { if (((Object)go).name == "Fabled Skeletal Captain") { cachedFabledCaptain = go; } return; } processedCaptains.Add(instanceID); if (((Object)go).name == "Fabled Skeletal Captain") { ForceAllNameFields(go, "Fabled Skeletal Captain"); ForceNameplateText(go, "Fabled Skeletal Captain"); ScaleStats(go); ApplyScale(go, 1.8f); InjectCelestialSmite(go); InjectGuaranteed(go, ref page1Ref, "11021645", "Pg.1"); cachedFabledCaptain = go; if (nextCaptainMsgAt <= 0f) { nextCaptainMsgAt = Time.time + 180f; } } else if (Random.value > 0.15f) { ShowNormalCaptainMessage(); } else { ((Object)go).name = "Fabled Skeletal Captain"; ForceAllNameFields(go, "Fabled Skeletal Captain"); ForceNameplateText(go, "Fabled Skeletal Captain"); ScaleStats(go); ApplyScale(go, 1.8f); InjectTalismanIntoDrops(go); InjectCelestialSmite(go); InjectGuaranteed(go, ref page1Ref, "11021645", "Pg.1"); ShowFabledCaptainMessage(); nextCaptainMsgAt = Time.time + 180f; cachedFabledCaptain = go; Debug.Log((object)"[BoneLordItems] ★ Captain → Fabled"); } } private static void HandleLazalith(GameObject go) { int instanceID = ((Object)go).GetInstanceID(); if (processedLazalith.Contains(instanceID)) { if (((Object)go).name == "Fabled Lazalith, Demon of Sivakaya") { cachedFabledLazalith = go; } return; } processedLazalith.Add(instanceID); if (((Object)go).name == "Fabled Lazalith, Demon of Sivakaya") { ForceAllNameFields(go, "Fabled Lazalith, Demon of Sivakaya"); ForceNameplateText(go, "Fabled Lazalith, Demon of Sivakaya"); ScaleStats(go); ForceLevel(go, 25); ApplyScale(go, 4f); InjectGuaranteed(go, ref page2Ref, "271648", "Pg.2"); cachedFabledLazalith = go; if (nextLazalithMsgAt <= 0f) { nextLazalithMsgAt = Time.time + 180f; } } else if (!(Random.value > 0.15f)) { ((Object)go).name = "Fabled Lazalith, Demon of Sivakaya"; ForceAllNameFields(go, "Fabled Lazalith, Demon of Sivakaya"); ForceNameplateText(go, "Fabled Lazalith, Demon of Sivakaya"); ScaleStats(go); ForceLevel(go, 25); ApplyScale(go, 4f); InjectVisageIntoDrops(go); InjectGuaranteed(go, ref page2Ref, "271648", "Pg.2"); ShowFabledLazalithMessage(); nextLazalithMsgAt = Time.time + 180f; cachedFabledLazalith = go; Debug.Log((object)"[BoneLordItems] ★ Lazalith → Fabled (Lv25, scale 4) [SaltedStrand]"); } } private static void HandleGuard(GameObject go) { if (((Object)go).name.StartsWith("Fabled") || ((Object)go).name == "Fabled Spectral King's Guard") { cachedFabledGuard = go; return; } int instanceID = ((Object)go).GetInstanceID(); if (!processedGuards.Contains(instanceID)) { processedGuards.Add(instanceID); if (!(Random.value > 0.5f)) { ((Object)go).name = "Fabled Spectral King's Guard"; ForceAllNameFields(go, "Fabled Spectral King's Guard"); ForceNameplateText(go, "Fabled Spectral King's Guard"); ScaleStats(go); ForceLevel(go, 23); ApplyScale(go, 1.8f); InjectSigilIntoDrops(go); ShowFabledGuardMessage(); nextGuardMsgAt = Time.time + 180f; cachedFabledGuard = go; Debug.Log((object)"[BoneLordItems] ★ Spectral Guard → Fabled (Lv23, 50%) [Undercity]"); } } } private static void ProcessFabledMessageTimersCached() { if (Time.frameCount % 180 == 0) { if (IsCachedAlive(ref cachedFabledCaptain) && Time.time >= nextCaptainMsgAt) { ShowFabledCaptainMessage(); nextCaptainMsgAt = Time.time + 180f; } if (IsCachedAlive(ref cachedFabledLazalith) && Time.time >= nextLazalithMsgAt) { ShowFabledLazalithMessage(); nextLazalithMsgAt = Time.time + 180f; } if (IsCachedAlive(ref cachedFabledPeon) && Time.time >= nextPeonMsgAt) { SendYellow("*** FABLED CRIMSON PEON'S BLOODLUST RISES AS HE YEARNS TO PAINT HIS BONES IN THE BLOOD OF ANY WHO DARE TO CHALLENGE HIS DOMAIN ***"); nextPeonMsgAt = Time.time + 180f; } if (IsCachedAlive(ref cachedFabledGuard) && Time.time >= nextGuardMsgAt) { ShowFabledGuardMessage(); nextGuardMsgAt = Time.time + 180f; } } } private static bool IsCachedAlive(ref GameObject go) { if ((Object)(object)go == (Object)null) { return false; } if (!Object.op_Implicit((Object)(object)go)) { go = null; return false; } if (!go.activeInHierarchy) { go = null; return false; } return true; } private static bool TrySpawnFireFx() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) Vector3 pos = default(Vector3); ((Vector3)(ref pos))..ctor(565.3357f, 24.5367f, 359.0786f); GameObject val = SpawnProp("FX_Fire_01", pos); if ((Object)(object)val == (Object)null) { return false; } val.transform.localScale = new Vector3(20f, 1f, 20f); val.transform.rotation = Quaternion.identity; GameObject val2 = SpawnProp("FX_Fire_Embers_01", pos); if ((Object)(object)val2 != (Object)null) { val2.transform.localScale = new Vector3(10f, 10f, 10f); val2.transform.rotation = Quaternion.Euler(270f, 0f, 0f); } return true; } private static void ProcessCrimsonPeon() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (Time.frameCount % 90 == 0 && !IsCachedAlive(ref cachedFabledPeon) && !(Time.time < nextPeonSpawnAt)) { Vector3 pos = default(Vector3); ((Vector3)(ref pos))..ctor(562.2698f, 24.1933f, 362.584f); GameObject val = SpawnNpc("Peon", pos); if (!((Object)(object)val == (Object)null)) { ((Object)val).name = "The Fabled Crimson Peon"; ForceAllNameFields(val, "The Fabled Crimson Peon"); ForceNameplateText(val, "The Fabled Crimson Peon"); ScaleStats(val); ForcePeonHP(val); ApplyScale(val, 2.5f); ForceLevel(val, 28); InjectAmuletRareOnly(val); SendYellow("*** FABLED CRIMSON PEON'S BLOODLUST RISES AS HE YEARNS TO PAINT HIS BONES IN THE BLOOD OF ANY WHO DARE TO CHALLENGE HIS DOMAIN ***"); nextPeonMsgAt = Time.time + 180f; nextPeonSpawnAt = Time.time + 600f; cachedFabledPeon = val; Debug.Log((object)"[BoneLordItems] ★ The Fabled Crimson Peon spawned (HP 30000, scale 2.5, 10-min timer)"); } } } private static void ForcePeonHP(GameObject go) { Component[] componentsInChildren = go.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); string[] array = new string[7] { "BaseHP", "CurrentMaxHP", "CurrentHP", "MaxHP", "HP", "Health", "MaxHealth" }; string[] array2 = array; foreach (string name in array2) { FieldInfo fieldInfo = FindField(type, name); if (fieldInfo != null && fieldInfo.FieldType == typeof(int)) { try { fieldInfo.SetValue(val, 30000); } catch { } } } } } private static void ApplyScale(GameObject root, float scale) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null) { return; } try { root.transform.localScale = new Vector3(scale, scale, scale); } catch { } } private static void ForceLevel(GameObject go, int level) { Component[] componentsInChildren = go.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } FieldInfo fieldInfo = FindField(((object)val).GetType(), "Level"); if (fieldInfo != null && fieldInfo.FieldType == typeof(int)) { try { fieldInfo.SetValue(val, level); } catch { } } } } private static GameObject SpawnNpc(string nameContains, Vector3 pos) { //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) GameObject[] array = Resources.FindObjectsOfTypeAll(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null) && ((Object)val).name.IndexOf(nameContains, StringComparison.OrdinalIgnoreCase) >= 0) { try { GameObject val2 = Object.Instantiate(val, pos, Quaternion.identity); val2.SetActive(true); return val2; } catch { } } } return null; } private static GameObject SpawnProp(string propName, Vector3 pos) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) GameObject[] array = Resources.FindObjectsOfTypeAll(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null) && ((Object)val).name.IndexOf(propName, StringComparison.OrdinalIgnoreCase) >= 0) { try { GameObject val2 = Object.Instantiate(val, pos, Quaternion.identity); val2.SetActive(true); return val2; } catch { } } } return null; } private static void ScaleStats(GameObject root) { Component[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); string name = type.Name; if (name != "Stats" && name != "Character" && name != "NPC") { continue; } string[] array = new string[18] { "BaseHP", "CurrentMaxHP", "CurrentHP", "MaxHP", "HP", "Health", "MaxHealth", "Strength", "Dexterity", "Endurance", "Agility", "Wisdom", "Intelligence", "AC", "Armor", "Attack", "Damage", "Level" }; string[] array2 = array; foreach (string text in array2) { FieldInfo fieldInfo = FindField(type, text); if (fieldInfo == null) { continue; } try { if (fieldInfo.FieldType == typeof(int)) { int num = (int)fieldInfo.GetValue(val); if (text.Contains("HP") || text.Contains("Health")) { fieldInfo.SetValue(val, 3048); continue; } int num2 = Mathf.RoundToInt((float)num * 1.5f); if (text == "Level") { num2 = Mathf.Max(num2, num + 4); } fieldInfo.SetValue(val, num2); } else if (fieldInfo.FieldType == typeof(float)) { fieldInfo.SetValue(val, (float)fieldInfo.GetValue(val) * 1.5f); } } catch { } } } } private static void InjectGuaranteed(GameObject npc, ref object itemRef, string id, string label) { if (itemRef == null) { itemRef = FindFirstByStringField("Id", id); } if (itemRef == null) { return; } string[] array = new string[6] { "GuaranteeOneDrop", "ActualDrops", "RareDrop", "UncommonDrop", "CommonDrop", "AlwaysDrop" }; Component[] componentsInChildren = npc.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null || ((object)val).GetType().Name != "LootTable") { continue; } string[] array2 = array; foreach (string text in array2) { FieldInfo fieldInfo = FindField(((object)val).GetType(), text); if (fieldInfo == null || !(fieldInfo.GetValue(val) is IList list)) { continue; } bool flag = false; foreach (object item in list) { if (item == itemRef) { flag = true; break; } } if (!flag) { list.Add(itemRef); Debug.Log((object)("[BoneLordItems] " + label + " added to " + text)); } } } } private static void InjectTalismanIntoDrops(GameObject npc) { if (talismanItemRef == null) { talismanItemRef = FindFirstByStringField("ItemName", "Talisman of the Bone Knight") ?? FindFirstByStringField("Id", "29042550"); } InjectToLoot(npc, talismanItemRef, "Talisman"); } private static void InjectVisageIntoDrops(GameObject npc) { if (visageItemRef == null) { visageItemRef = FindFirstByStringField("ItemName", "Visage of the Gnoll God") ?? FindFirstByStringField("Id", "57247840"); } InjectToLoot(npc, visageItemRef, "Visage"); } private static void InjectAmuletRareOnly(GameObject npc) { if (amuletItemRef == null) { amuletItemRef = FindFirstByStringField("ItemName", "Amulet of Necropotence") ?? FindFirstByStringField("Id", "20832306"); } if (amuletItemRef == null) { return; } Component[] componentsInChildren = npc.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null || ((object)val).GetType().Name != "LootTable") { continue; } FieldInfo fieldInfo = FindField(((object)val).GetType(), "RareDrop"); if (fieldInfo == null || !(fieldInfo.GetValue(val) is IList list)) { continue; } bool flag = false; foreach (object item in list) { if (item == amuletItemRef) { flag = true; break; } } if (!flag) { list.Add(amuletItemRef); Debug.Log((object)"[BoneLordItems] Amulet added to RareDrop only (~5%)"); } } } private static void InjectSigilIntoDrops(GameObject npc) { if (sigilItemRef == null) { sigilItemRef = FindFirstByStringField("ItemName", "Sigil of the Anguished Shade") ?? FindFirstByStringField("Id", "14265295"); } InjectToLoot(npc, sigilItemRef, "Sigil"); } private static void InjectToLoot(GameObject npc, object itemRef, string label) { if (itemRef == null) { return; } string[] array = new string[4] { "RareDrop", "UncommonDrop", "CommonDrop", "ActualDrops" }; Component[] componentsInChildren = npc.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null || ((object)val).GetType().Name != "LootTable") { continue; } string[] array2 = array; foreach (string text in array2) { FieldInfo fieldInfo = FindField(((object)val).GetType(), text); if (fieldInfo == null || !(fieldInfo.GetValue(val) is IList list)) { continue; } bool flag = false; foreach (object item in list) { if (item == itemRef) { flag = true; break; } } if (!flag) { list.Add(itemRef); Debug.Log((object)("[BoneLordItems] " + label + " added to " + text)); } } } } private static void InjectCelestialSmite(GameObject npc) { if (celestialSmiteRef == null) { celestialSmiteRef = FindFirstByStringField("Id", "11565860") ?? FindFirstByStringField("SpellName", "Celestial Smite I"); } if (celestialSmiteRef == null) { return; } string[] array = new string[8] { "Spells", "SpellList", "KnownSpells", "Abilities", "Skills", "SpellBook", "CombatSpells", "NPCSpells" }; Component[] componentsInChildren = npc.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } string[] array2 = array; foreach (string name in array2) { FieldInfo fieldInfo = FindField(((object)val).GetType(), name); if (fieldInfo == null || !(fieldInfo.GetValue(val) is IList list)) { continue; } bool flag = false; foreach (object item in list) { if (item == celestialSmiteRef) { flag = true; break; } } if (!flag) { try { list.Add(celestialSmiteRef); } catch { } } } } } private static void ShowBonepitsSenseMessage() { SendYellow("*** YOU SENSE A FABLED MAGIC STIRRING IN THE BONEPITS... ANCIENT POWER AWAKENS BENEATH THE DUST AND BONE. ***"); } private static void ShowFabledCaptainMessage() { SendYellow("*** A FABLED SKELETAL CAPTAIN RAISES HIS RUSTED BLADE AND BELLOWS A DEFIANT CHALLENGE, DARING ANY ADVENTURER TO TEST THEIR MIGHT AGAINST HIS ANCIENT BONES! ***"); } private static void ShowNormalCaptainMessage() { SendYellow("*** A SKELETON CAPTAIN'S HOLLOW EYES GLEAM WITH THE FAINT ECHOES OF FABLED MEMORIES, AS IF RECALLING A TIME WHEN TRUE POWER STILL WALKED THESE HALLS. ***"); } private static void ShowFabledLazalithMessage() { SendYellow("*** A DEMONIC HOWL ECHOES AS FABLED LAZALITH, DEMON OF SIVAKAYA, AWAKENS ***"); } private static void ShowFabledGuardMessage() { SendYellow("*** A COLD WAIL DRIFTS THROUGH THE UNDERCITY AS THE FABLED SPECTRAL KING'S GUARD MANIFESTS ***"); } private static void SendYellow(string msg) { try { Type type = Type.GetType("UpdateSocialLog, Assembly-CSharp"); if (type == null) { return; } MethodInfo method = type.GetMethod("LogAdd", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(string) }, null); if (method != null) { method.Invoke(null, new object[2] { msg, "yellow" }); return; } method = type.GetMethod("LogAdd", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (method != null) { method.Invoke(null, new object[1] { msg }); } } catch { } } private static void ForceAllNameFields(GameObject root, string newName) { Component[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { Type type = ((object)val).GetType(); string[] array = new string[11] { "Name", "DisplayName", "NPCName", "CharacterName", "MyName", "ActorName", "UnitName", "EntityName", "m_Name", "VisibleName", "Title" }; string[] array2 = array; foreach (string fieldName in array2) { Set(val, type, fieldName, newName); } } } } private static void ForceNameplateText(GameObject root, string newName) { Component[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } string name = ((object)val).GetType().Name; if (!(name == "Text") && !name.Contains("TextMeshPro") && !name.Contains("TMP_Text") && !(name == "TextMesh")) { continue; } try { PropertyInfo property = ((object)val).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public); if (property != null) { string text = property.GetValue(val, null) as string; if (!string.IsNullOrEmpty(text) && (text.Contains("Captain") || text.Contains("Lazalith") || text.Contains("Peon") || text.Contains("Guard") || text.Contains("Skeleton"))) { property.SetValue(val, newName, null); } } } catch { } } } private static bool LooksLikeGameDataPresent() { try { Type type = Type.GetType("GameData, Assembly-CSharp"); if (type != null) { FieldInfo field = type.GetField("PlayerStats", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.GetValue(null) != null) { return true; } } } catch { } return FindFirstByStringField("ItemName", "Soul Echo") != null || FindFirstByStringField("Id", "20309875") != null; } private static int InjectEverything() { object obj = FindHydrated(); if (obj == null) { return 0; } int num = 0; object classesTemplate = FindClassesTemplate(); if (cloneSkeleton == null) { cloneSkeleton = MakeClone(obj, "90000001", "Amulet of Necropotence", "Skeleton", "You take the form of Nazura the Traitor."); } if (cloneKnight == null) { cloneKnight = MakeClone(obj, "90000002", "Talisman of the Bone Knight", "SkeletonKnight", "You take the form of a Skeleton Knight."); } if (cloneHero == null) { cloneHero = MakeClone(obj, "90000003", "Visage of the Gnoll God", "HeroKnightFemale", "You take the form of the Gnoll God."); } if (cloneTorment == null) { cloneTorment = MakeClone(obj, "90000004", "Sigil of the Anguished Shade", "TormentedSoul", "You take the form of an Anguished Shade."); } if (cloneSkeleton == null || cloneKnight == null || cloneHero == null || cloneTorment == null) { return 0; } num += 4; num += ModItem("20832306", "Soul Echo", "Amulet of Necropotence", "Click: Become Nazura the Traitor.", classesTemplate, cloneSkeleton); num += ModItem("29042550", "Neophyte Necklace", "Talisman of the Bone Knight", "Click: Skeleton Knight form.", classesTemplate, cloneKnight); num += ModItem("57247840", "Fluorite Amulet", "Visage of the Gnoll God", "Click: Gnoll God form.", classesTemplate, cloneHero); num += ModItem("14265295", "Plain Necklace", "Sigil of the Anguished Shade", "Click: Anguished Shade form.", classesTemplate, cloneTorment); num += ModItemByName("Amulet of Necropotence", "Amulet of Necropotence", "Click: Become Nazura the Traitor.", classesTemplate, cloneSkeleton); num += ModItemByName("Talisman of the Bone Knight", "Talisman of the Bone Knight", "Click: Skeleton Knight form.", classesTemplate, cloneKnight); num += ModItemByName("Visage of Anubis", "Visage of the Gnoll God", "Click: Gnoll God form.", classesTemplate, cloneHero); num += ModItemByName("Visage of the Gnoll God", "Visage of the Gnoll God", "Click: Gnoll God form.", classesTemplate, cloneHero); num += ModItemByName("Sigil of the Anguished Shade", "Sigil of the Anguished Shade", "Click: Anguished Shade form.", classesTemplate, cloneTorment); num += ModItemByName("Wail of the Tormented", "Sigil of the Anguished Shade", "Click: Anguished Shade form.", classesTemplate, cloneTorment); num += UpdatePage1Lore(); return num + UpdateMathersNoteLore(); } private static int UpdatePage1Lore() { int num = 0; string value = "******** You pick up a faded page from a family journal. Seek out the descendants of the Fabled Captain Mathers. They may hold knowledge of the fabled magic you have encountered. The page is dusted with black salt, and a faded photograph of a seaside cottage is carefully tucked within. ********"; foreach (object item in FindAllByStringField("Id", "11021645")) { Type type = item.GetType(); Set(item, type, "Lore", value); Set(item, type, "ItemLore", value); Set(item, type, "Description", value); Set(item, type, "Desc", value); num++; Debug.Log((object)"[BoneLordItems] Updated Pg.1 Faded Entry lore (ID 11021645)"); } return num; } private static int UpdateMathersNoteLore() { int num = 0; string value = "******** Strange Fabled Magic permeates this note, continue investigating the Mathers to track down the source of this magic****I fear for our safety. I fear that our time is nearing its end. \n\nThere have been cloaked figures lurking on the beach at night, after dark. I wonder if they know what knowledge I possess... and how they plan to extract it from me. I can only wonder what Eldoth has asked of them...\n\nIf you find this letter after my demise, see my Brother Yarren in Goodsoil. I've given something of great interest to him for safe keeping. Ask for him - he's often toiling away out of sight."; foreach (object item in FindAllByStringFieldContains("ItemName", "Mathers")) { Type type = item.GetType(); Set(item, type, "Lore", value); Set(item, type, "ItemLore", value); Set(item, type, "Description", value); Set(item, type, "Desc", value); num++; Debug.Log((object)"[BoneLordItems] Updated Mathers Note lore (found by ItemName)"); } if (num == 0) { string[] array = new string[4] { "Mathers Note", "Mathers' Note", "Note from Mathers", "A Mathers Note" }; string[] array2 = array; foreach (string text in array2) { foreach (object item2 in FindAllByStringField("ItemName", text)) { Type type2 = item2.GetType(); Set(item2, type2, "Lore", value); Set(item2, type2, "ItemLore", value); Set(item2, type2, "Description", value); Set(item2, type2, "Desc", value); num++; Debug.Log((object)("[BoneLordItems] Updated Mathers Note lore (name match: " + text + ")")); } } } if (num == 0) { Debug.LogWarning((object)"[BoneLordItems] Mathers Note not found by name – open it in Unity Explorer and tell me the exact ItemName or Id string"); } return num; } private static object FindHydrated() { using (IEnumerator enumerator = FindAllByStringField("Id", "20309875").GetEnumerator()) { if (enumerator.MoveNext()) { return enumerator.Current; } } string[] array = new string[2] { "SpellName", "Name" }; foreach (string fieldName in array) { using IEnumerator enumerator2 = FindAllByStringField(fieldName, "Hydrated").GetEnumerator(); if (enumerator2.MoveNext()) { return enumerator2.Current; } } return null; } private static object MakeClone(object template, string newId, string newName, string form, string msg) { try { ScriptableObject val = (ScriptableObject)((template is ScriptableObject) ? template : null); if ((Object)(object)val == (Object)null) { return null; } ScriptableObject val2 = Object.Instantiate(val); ((Object)val2).name = newName; Type type = ((object)val2).GetType(); Set(val2, type, "Id", newId); Set(val2, type, "SpellName", newName); Set(val2, type, "Name", newName); Set(val2, type, "ShapeshiftForm", form); Set(val2, type, "StatusEffectMessageOnPlayer", msg); Set(val2, type, "SpellDesc", msg); Set(val2, type, "Lore", msg); Set(val2, type, "SelfOnly", true); Set(val2, type, "InflictOnSelf", true); Set(val2, type, "ApplyToCaster", true); Set(val2, type, "GroupEffect", false); Set(val2, type, "TargetDamage", 0); Set(val2, type, "Damage", 0); Set(val2, type, "HealAmount", 0); Set(val2, type, "ManaCost", 0); Set(val2, type, "SpellDurationInTicks", 3600); Set(val2, type, "Duration", 3600f); Set(val2, type, "IsBuff", true); Set(val2, type, "Beneficial", true); Set(val2, type, "IsStatusEffect", true); Debug.Log((object)("[BoneLordItems] ✓ Clone " + newName + " form=" + form)); return val2; } catch (Exception ex) { Debug.LogError((object)("[BoneLordItems] Clone failed: " + ex)); return null; } } private static int ModItem(string id, string oldName, string newName, string lore, object classesTemplate, object spellRef) { int num = 0; foreach (object item in FindAllByStringField("Id", id)) { if (ApplyItem(item, newName, lore, classesTemplate, spellRef)) { num++; } } return num; } private static int ModItemByName(string name, string newName, string lore, object classesTemplate, object spellRef) { int num = 0; foreach (object item in FindAllByStringField("ItemName", name)) { if (ApplyItem(item, newName, lore, classesTemplate, spellRef)) { num++; } } return num; } private static bool ApplyItem(object item, string newName, string lore, object classesTemplate, object spellRef) { Type type = item.GetType(); Set(item, type, "ItemName", newName); Set(item, type, "Lore", lore); Set(item, type, "Relic", true); Set(item, type, "RareItem", true); if (classesTemplate != null) { FieldInfo fieldInfo = FindField(type, "Classes"); if (fieldInfo != null) { try { fieldInfo.SetValue(item, classesTemplate); } catch { } } } if (spellRef != null) { Set(item, type, "ItemEffectOnClick", spellRef); Set(item, type, "SpellOnClick", spellRef); Set(item, type, "OnClickSpell", spellRef); Set(item, type, "ClickSpell", spellRef); } return true; } private static object FindClassesTemplate() { Object[] array = Resources.FindObjectsOfTypeAll(typeof(ScriptableObject)); foreach (Object val in array) { if (val == (Object)null) { continue; } FieldInfo fieldInfo = FindField(((object)val).GetType(), "Classes"); if (!(fieldInfo == null)) { object value = fieldInfo.GetValue(val); if (value is IList { Count: >=6 }) { return value; } } } return null; } private static object FindFirstByStringField(string fieldName, string value) { using (IEnumerator enumerator = FindAllByStringField(fieldName, value).GetEnumerator()) { if (enumerator.MoveNext()) { return enumerator.Current; } } return null; } private static IEnumerable FindAllByStringField(string fieldName, string value) { List list = new List(); Object[] array = Resources.FindObjectsOfTypeAll(typeof(ScriptableObject)); foreach (Object val in array) { if (!(val == (Object)null)) { FieldInfo fieldInfo = FindField(((object)val).GetType(), fieldName); if (!(fieldInfo == null) && !(fieldInfo.FieldType != typeof(string)) && fieldInfo.GetValue(val) as string == value) { list.Add(val); } } } return list; } private static IEnumerable FindAllByStringFieldContains(string fieldName, string contains) { List list = new List(); Object[] array = Resources.FindObjectsOfTypeAll(typeof(ScriptableObject)); foreach (Object val in array) { if (val == (Object)null) { continue; } FieldInfo fieldInfo = FindField(((object)val).GetType(), fieldName); if (!(fieldInfo == null) && !(fieldInfo.FieldType != typeof(string))) { string text = fieldInfo.GetValue(val) as string; if (!string.IsNullOrEmpty(text) && text.IndexOf(contains, StringComparison.OrdinalIgnoreCase) >= 0) { list.Add(val); } } } return list; } private static FieldInfo FindField(Type type, string name) { while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } return null; } private static void Set(object obj, Type type, string fieldName, object value) { FieldInfo fieldInfo = FindField(type, fieldName); if (fieldInfo == null) { return; } try { if (value == null) { if (!fieldInfo.FieldType.IsValueType) { fieldInfo.SetValue(obj, null); } } else if (fieldInfo.FieldType == typeof(bool) && value is bool flag) { fieldInfo.SetValue(obj, flag); } else if (fieldInfo.FieldType == typeof(int) && value is int num) { fieldInfo.SetValue(obj, num); } else if (fieldInfo.FieldType == typeof(float) && value is float num2) { fieldInfo.SetValue(obj, num2); } else if (fieldInfo.FieldType.IsAssignableFrom(value.GetType())) { fieldInfo.SetValue(obj, value); } else { fieldInfo.SetValue(obj, Convert.ChangeType(value, fieldInfo.FieldType)); } } catch { } } }