using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using HarmonyLib; using UnityEngine; using UnityEngine.AI; 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("SkeletonShapeshift")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SkeletonShapeshift")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("95a4b4eb-c4f8-4021-a033-971d6730881a")] [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 SkeletonShapeshift; [BepInPlugin("com.yourname.skeletonshapeshift", "Skeleton Shapeshift", "1.23.6")] public class Plugin : BaseUnityPlugin { private class IllusionDef { public string FormKey; public string PrimaryMesh; public string[] FallbackMeshes; public float AttackHitChance; public bool UseSkeletonSfx; public string SpawnWav; public string AttackWav; } private static bool isInSkeletonForm = false; private static float nextCheckTime = 0f; private static float graceUntil = 0f; private static int missingBuffStrikes = 0; private static GameObject currentClone = null; private static bool hadPlayerStats = false; private static List attachedWeapons = new List(); private static float nextSoundTime = 0f; private static float nextAttackSfxTime = 0f; private static float weaponCycleCooldownUntil = 0f; private static bool weaponCycleRunning = false; private static bool pendingF7Cycle = false; private static bool visualPatchDone = false; private static bool suppressNextSpawn = false; private static string lastEquipSig = ""; private static float nextEquipPoll = 0f; private static bool fpvActive = false; private static readonly List humanRenderersHidden = new List(); private const float FPV_CLOSE_DISTANCE = 2f; private static string currentPrimaryMesh = "SM_Chr_Skeleton_LightArmor_01"; private static string currentFormKey = "Skeleton"; private static float currentAttackChance = 0.1f; private static AudioClip currentSpawnClip = null; private static AudioClip currentAttackClip = null; private static AudioClip skeletonLaugh = null; private static AudioClip skeletonAttack = null; private static AudioClip tormentedSpawn = null; private static AudioClip tormentedAttack = null; private static AudioClip heroFemaleSpawn = null; private static AudioClip heroFemaleAttack = null; private static AudioClip dingClip = null; private static bool soundLoadStarted = false; private static AudioSource sfxSource = null; private static int lastKnownLevel = -1; private static string lastSpawnFormKey = ""; private static float spawnSfxReadyAt = 0f; private static Harmony harmonyInstance; private static GameObject ancientWarriorTemplateCache = null; private static string ancientWarriorCacheSourceName = ""; private static GameObject nazuraTemplateCache = null; private static string nazuraCacheSourceName = ""; private const float FORCE_SCALE = 1f; private const float LAUGH_INTERVAL = 120f; private const float LOGIN_SFX_GRACE = 6f; private const float ATTACK_SFX_COOLDOWN = 0.85f; private const float WEAPON_CYCLE_COOLDOWN = 0.85f; private const float EQUIP_POLL_INTERVAL = 0.15f; private const float ANCIENT_WARRIOR_WEAPON_SCALE = 0.01f; private static readonly Vector3 ANCIENT_WARRIOR_OFFSET_RIGHT = new Vector3(0.1023f, 0.0385f, -0.0424f); private static readonly Vector3 ANCIENT_WARRIOR_OFFSET_LEFT = new Vector3(-0.0909f, -0.0388f, 0.0089f); private static readonly IllusionDef[] IllusionList = new IllusionDef[4] { new IllusionDef { FormKey = "Skeleton", PrimaryMesh = "SM_Chr_Skeleton_LightArmor_01", FallbackMeshes = new string[5] { "SM_Chr_Skeleton_LightArmor_01", "Character_Skeleton_Slave_01", "Character_Skeleton_Knight", "Character_Skeleton_Soldier_01", "Skeleton" }, AttackHitChance = 0.1f, UseSkeletonSfx = true, SpawnWav = "Skeleton_laugh", AttackWav = "Skeleton_Attack" }, new IllusionDef { FormKey = "SkeletonKnight", PrimaryMesh = "Character_Skeleton_Knight", FallbackMeshes = new string[3] { "Character_Skeleton_Slave_01", "Character_Skeleton_Soldier_01", "Skeleton" }, AttackHitChance = 0.1f, UseSkeletonSfx = true, SpawnWav = "Skeleton_laugh", AttackWav = "Skeleton_Attack" }, new IllusionDef { FormKey = "TormentedSoul", PrimaryMesh = "Character_Tormented_Soul", FallbackMeshes = new string[3] { "Character_Ghost_02", "Character_Ghost_01", "Character_Tormented_Soul" }, AttackHitChance = 0.1f, UseSkeletonSfx = false, SpawnWav = "TormentedSpawn", AttackWav = "TormentedAttack" }, new IllusionDef { FormKey = "HeroKnightFemale", PrimaryMesh = "Character_Ancient_Warrior_01", FallbackMeshes = new string[3] { "Character_DarkElf_01", "Character_Hero_Knight_Female", "Character_Skeleton_Knight" }, AttackHitChance = 0.1f, UseSkeletonSfx = false, SpawnWav = "HeroFemaleSpawn", AttackWav = "HeroFemaleAttack" } }; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown harmonyInstance = new Harmony("com.yourname.skeletonshapeshift"); foreach (MethodInfo item in from m in typeof(Stats).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "AddStatusEffect" select m) { harmonyInstance.Patch((MethodBase)item, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "PostfixAddStatusEffect", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo method = typeof(Plugin).GetMethod("PostfixDamageMe", BindingFlags.Static | BindingFlags.Public); int num = 0; foreach (MethodInfo item2 in from m in typeof(Character).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "DamageMe" select m) { harmonyInstance.Patch((MethodBase)item2, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } Debug.Log((object)("[SkeletonMod] Patched Character.DamageMe overloads: " + num)); EnsureSfxSource(); TryLoadSounds(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Skeleton Shapeshift 1.23.6 loaded (all attack SFX 10% on hit)"); } private static void TryPatchUpdatePlayerVisuals() { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown if (visualPatchDone || harmonyInstance == null || (Object)(object)GameData.PlayerInv == (Object)null) { return; } object obj = null; try { Type type = ((object)GameData.PlayerInv).GetType(); obj = type.GetField("Modulars", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerInv) ?? type.GetProperty("Modulars", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerInv, null); } catch { return; } if (obj == null) { return; } int num = 0; try { foreach (MethodInfo item in from x in obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where x.Name == "UpdatePlayerVisuals" select x) { harmonyInstance.Patch((MethodBase)item, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "PostfixUpdatePlayerVisuals", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } } catch { return; } visualPatchDone = true; Debug.Log((object)("[SkeletonMod] Patched UpdatePlayerVisuals overloads: " + num)); } public static void PostfixUpdatePlayerVisuals() { if (isInSkeletonForm && !weaponCycleRunning && IsGameplayWorld()) { QueueIfEquipChanged("UpdatePlayerVisuals"); } } private static void QueueIfEquipChanged(string reason) { if (isInSkeletonForm && !weaponCycleRunning && !(Time.time < weaponCycleCooldownUntil) && IsGameplayWorld()) { string text = BuildEquipSignature(); if (!string.IsNullOrEmpty(text) && !(text == lastEquipSig)) { lastEquipSig = text; pendingF7Cycle = true; Debug.Log((object)("[SkeletonMod][Weapons] EQUIP CHANGED (" + reason + ") → queue F6 | " + text)); } } } private static string BuildEquipSignature() { string text = BuildSignatureFromEquipmentSlots(weaponSlotsOnly: true); if (!string.IsNullOrEmpty(text)) { return text; } string text2 = BuildSignatureFromEquipmentSlots(weaponSlotsOnly: false); if (!string.IsNullOrEmpty(text2)) { return text2; } return BuildSignatureFromUiSlots(); } private static string BuildSignatureFromEquipmentSlots(bool weaponSlotsOnly) { try { if ((Object)(object)GameData.PlayerInv == (Object)null) { return ""; } Type type = ((object)GameData.PlayerInv).GetType(); object obj = type.GetField("EquipmentSlots", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerInv) ?? type.GetProperty("EquipmentSlots", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerInv, null); if (!(obj is IList { Count: not 0 } list)) { return ""; } StringBuilder stringBuilder = new StringBuilder(); int num = 0; for (int i = 0; i < list.Count; i++) { object obj2 = list[i]; if (obj2 == null) { continue; } string slotKey = GetSlotKey(obj2, i); if (!weaponSlotsOnly || IsPrimaryOrSecondaryKey(slotKey)) { string text = DescribeSlotItem(obj2); if (!(text == "empty") && !string.IsNullOrEmpty(text)) { stringBuilder.Append(slotKey).Append('=').Append(text) .Append(';'); num++; } } } return (num > 0) ? stringBuilder.ToString() : ""; } catch { return ""; } } private static string BuildSignatureFromUiSlots() { try { if ((Object)(object)GameData.PlayerInv == (Object)null) { return ""; } Inventory playerInv = GameData.PlayerInv; Transform val = ((playerInv != null) ? ((Component)playerInv).transform : null); if ((Object)(object)val == (Object)null) { return ""; } StringBuilder stringBuilder = new StringBuilder(); int num = 0; string[] array = new string[6] { "Primary", "Secondary", "MainHand", "OffHand", "mainhand", "offhand" }; foreach (string text in array) { Transform val2 = FindDeepChild(val, text); if (!((Object)(object)val2 == (Object)null)) { string value = ReadUiSlotIcon(((Component)val2).gameObject); if (!string.IsNullOrEmpty(value)) { stringBuilder.Append(text).Append('=').Append(value) .Append(';'); num++; } } } return (num > 0) ? stringBuilder.ToString() : ""; } catch { return ""; } } private static string BuildSignatureFromHumanHands() { try { Transform humanRoot = GetHumanRoot(); if ((Object)(object)humanRoot == (Object)null) { return ""; } Transform hand = FindDeepChild(humanRoot, "Hand_R") ?? FindDeepChild(humanRoot, "hand_r"); Transform hand2 = FindDeepChild(humanRoot, "Hand_L") ?? FindDeepChild(humanRoot, "hand_l"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("R="); AppendHandWeaponNames(hand, stringBuilder); stringBuilder.Append(";L="); AppendHandWeaponNames(hand2, stringBuilder); string text = stringBuilder.ToString(); return (text == "R=;L=") ? "" : text; } catch { return ""; } } private static void AppendHandWeaponNames(Transform hand, StringBuilder sb) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown if ((Object)(object)hand == (Object)null) { return; } bool flag = true; foreach (Transform item in hand) { Transform val = item; if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeSelf) { continue; } string text = ((Object)val).name.ToLowerInvariant(); if (!text.Contains("hand") && !text.Contains("finger") && !text.Contains("wrist") && (!((Object)(object)((Component)val).GetComponentInChildren(true) == (Object)null) || !((Object)(object)((Component)val).GetComponentInChildren(true) == (Object)null))) { if (!flag) { sb.Append('+'); } sb.Append(((Object)val).name); flag = false; } } } private static string ReadUiSlotIcon(GameObject slotGo) { if ((Object)(object)slotGo == (Object)null) { return ""; } try { Component[] componentsInChildren = slotGo.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } string name = ((object)val).GetType().Name; if (name != "Image" && name != "RawImage") { continue; } PropertyInfo property = ((object)val).GetType().GetProperty("sprite", BindingFlags.Instance | BindingFlags.Public); if (!(property != null)) { continue; } object value = property.GetValue(val, null); if (value != null) { string text = value.GetType().GetProperty("name")?.GetValue(value, null) as string; if (!string.IsNullOrEmpty(text)) { return text; } } } Transform val2 = FindDeepChild(slotGo.transform, "ItemIcon"); if ((Object)(object)val2 != (Object)null) { Component[] components = ((Component)val2).GetComponents(); foreach (Component val3 in components) { if ((Object)(object)val3 == (Object)null) { continue; } object obj = ((object)val3).GetType().GetProperty("sprite", BindingFlags.Instance | BindingFlags.Public)?.GetValue(val3, null); if (obj != null) { string text2 = obj.GetType().GetProperty("name")?.GetValue(obj, null) as string; if (!string.IsNullOrEmpty(text2)) { return text2; } } } } } catch { } return ""; } private static string GetSlotKey(object slot, int index) { try { Type type = slot.GetType(); string[] array = new string[6] { "SlotName", "MySlot", "slotName", "Name", "SlotType", "Type" }; foreach (string name in array) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(slot); if (value != null && !string.IsNullOrEmpty(value.ToString())) { return value.ToString(); } } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value2 = property.GetValue(slot, null); if (value2 != null && !string.IsNullOrEmpty(value2.ToString())) { return value2.ToString(); } } } Component val = (Component)((slot is Component) ? slot : null); if (val != null && (Object)(object)val.gameObject != (Object)null) { return ((Object)val.gameObject).name; } } catch { } return "idx" + index; } private static bool IsPrimaryOrSecondaryKey(string key) { if (string.IsNullOrEmpty(key)) { return false; } string text = key.ToLowerInvariant(); int result; if (!text.Contains("primary") && !text.Contains("secondary") && !text.Contains("mainhand") && !text.Contains("main_hand") && !text.Contains("main hand") && !text.Contains("offhand") && !text.Contains("off_hand") && !text.Contains("off hand")) { switch (text) { case "weapon": case "weapon1": case "weapon2": goto IL_00eb; } if (!text.Contains("righthand") && !text.Contains("lefthand") && !text.Contains("r_hand")) { result = (text.Contains("l_hand") ? 1 : 0); goto IL_00ec; } } goto IL_00eb; IL_00ec: return (byte)result != 0; IL_00eb: result = 1; goto IL_00ec; } private static string DescribeSlotItem(object slot) { try { Type type = slot.GetType(); string[] array = new string[6] { "MyItem", "Item", "item", "CurrentItem", "EquippedItem", "Content" }; foreach (string name in array) { object obj = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(slot) ?? type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(slot, null); if (obj != null) { Type type2 = obj.GetType(); FieldInfo fieldInfo = type2.GetField("Id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetField("ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); return string.Concat(str2: (type2.GetField("ItemName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetField("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(obj)?.ToString() ?? obj.ToString(), str0: fieldInfo?.GetValue(obj)?.ToString(), str1: ":"); } } } catch { } return "empty"; } private static void ForceUpdatePlayerVisuals() { try { if ((Object)(object)GameData.PlayerInv == (Object)null) { return; } Type type = ((object)GameData.PlayerInv).GetType(); object obj = type.GetField("Modulars", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerInv) ?? type.GetProperty("Modulars", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerInv, null); if (obj == null) { return; } object obj2 = type.GetField("EquipmentSlots", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerInv) ?? type.GetProperty("EquipmentSlots", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerInv, null); MethodInfo method = obj.GetType().GetMethod("UpdatePlayerVisuals", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(method == null)) { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 0) { method.Invoke(obj, null); } else if (parameters.Length >= 1 && obj2 != null) { method.Invoke(obj, new object[1] { obj2 }); } } } catch { } } private static ShapeshiftMngr GetShapeShift() { try { if ((Object)(object)GameData.PlayerStats == (Object)null) { return null; } object? obj = typeof(Stats).GetField("MyShapeShift", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(GameData.PlayerStats); return (ShapeshiftMngr)((obj is ShapeshiftMngr) ? obj : null); } catch { return null; } } private static bool IsCameraInFpv() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0030: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)GameData.PlayerControl != (Object)null) ? ((Component)GameData.PlayerControl).transform.position : Vector3.zero); Vector3 val2 = val + Vector3.up * 1.55f; Camera[] array = null; try { array = Camera.allCameras; } catch { } if (array == null || array.Length == 0) { Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return false; } array = (Camera[])(object)new Camera[1] { main }; } Camera[] array2 = array; foreach (Camera val3 in array2) { if (!((Object)(object)val3 == (Object)null) && ((Behaviour)val3).enabled && ((Component)val3).gameObject.activeInHierarchy && !val3.orthographic) { float num = Vector3.Distance(((Component)val3).transform.position, val2); if (num < 2f) { return true; } } } return false; } private static void HideHumanBodyRenderers(Transform playerRoot) { humanRenderersHidden.Clear(); if ((Object)(object)playerRoot == (Object)null) { return; } Renderer[] componentsInChildren = ((Component)playerRoot).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { string text = ((Object)((Component)val).gameObject).name.ToLowerInvariant(); if (!text.Contains("canvas") && !text.Contains("ui") && !text.Contains("text") && val.enabled) { val.enabled = false; humanRenderersHidden.Add(val); } } } } private static void RestoreHumanBodyRenderers() { foreach (Renderer item in humanRenderersHidden) { if ((Object)(object)item != (Object)null) { item.enabled = true; } } humanRenderersHidden.Clear(); } private static void EnterFpvMode() { if (fpvActive || weaponCycleRunning) { return; } ShapeshiftMngr shapeShift = GetShapeShift(); if (!((Object)(object)shapeShift == (Object)null)) { if ((Object)(object)currentClone != (Object)null) { currentClone.SetActive(false); } if ((Object)(object)shapeShift.PlayerRoot != (Object)null) { shapeShift.PlayerRoot.SetActive(true); HideHumanBodyRenderers(shapeShift.PlayerRoot.transform); } fpvActive = true; Debug.Log((object)"[SkeletonMod][FPV] Enter FPV (PlayerRoot on, clone hidden, human meshes off)"); } } private static void ExitFpvMode() { if (!fpvActive) { return; } ShapeshiftMngr shapeShift = GetShapeShift(); RestoreHumanBodyRenderers(); if ((Object)(object)shapeShift != (Object)null && (Object)(object)shapeShift.PlayerRoot != (Object)null) { shapeShift.PlayerRoot.SetActive(false); } if ((Object)(object)currentClone != (Object)null) { currentClone.SetActive(true); if ((Object)(object)shapeShift != (Object)null) { shapeShift.CurrentModel = currentClone; } } fpvActive = false; Debug.Log((object)"[SkeletonMod][FPV] Exit FPV (clone shown, PlayerRoot off)"); } private static void UpdateFpvMode() { if (!isInSkeletonForm || (Object)(object)currentClone == (Object)null || weaponCycleRunning) { if (fpvActive) { ExitFpvMode(); } return; } bool flag = IsCameraInFpv(); if (flag && !fpvActive) { EnterFpvMode(); } else if (!flag && fpvActive) { ExitFpvMode(); } } private static void ClearFpvState() { if (fpvActive) { ExitFpvMode(); } RestoreHumanBodyRenderers(); fpvActive = false; } private void Update() { if (!soundLoadStarted) { soundLoadStarted = true; EnsureSfxSource(); TryLoadSounds(); } if (!visualPatchDone && (Object)(object)GameData.PlayerInv != (Object)null) { TryPatchUpdatePlayerVisuals(); } if ((Object)(object)GameData.PlayerStats == (Object)null) { if (hadPlayerStats) { hadPlayerStats = false; isInSkeletonForm = false; lastKnownLevel = -1; lastEquipSig = ""; weaponCycleRunning = false; pendingF7Cycle = false; ClearFpvState(); CleanupWeapons(); if ((Object)(object)currentClone != (Object)null) { Object.Destroy((Object)(object)currentClone); currentClone = null; } } return; } if (!hadPlayerStats) { hadPlayerStats = true; spawnSfxReadyAt = Time.time + 6f; lastKnownLevel = GameData.PlayerStats.Level; } CheckLevelUpDing(); if (isInSkeletonForm && IsGameplayWorld()) { UpdateFpvMode(); } if (!IsGameplayWorld()) { if (isInSkeletonForm || (Object)(object)currentClone != (Object)null) { RestoreHumanForm(); } pendingF7Cycle = false; return; } if (isInSkeletonForm && !weaponCycleRunning && !fpvActive && Time.unscaledTime >= nextEquipPoll) { nextEquipPoll = Time.unscaledTime + 0.15f; QueueIfEquipChanged("poll"); } if (pendingF7Cycle && isInSkeletonForm && !weaponCycleRunning && !fpvActive && Time.time >= weaponCycleCooldownUntil) { pendingF7Cycle = false; weaponCycleCooldownUntil = Time.time + 0.85f; Debug.Log((object)"[SkeletonMod][Weapons] Running F6-cycle (auto)"); ((MonoBehaviour)this).StartCoroutine(F7StyleWeaponRefreshFast()); } else if (pendingF7Cycle && !isInSkeletonForm) { pendingF7Cycle = false; } if (!(Time.time >= nextCheckTime)) { return; } nextCheckTime = Time.time + 0.35f; if (HasIllusionBuff()) { missingBuffStrikes = 0; if (!weaponCycleRunning && !fpvActive && (!isInSkeletonForm || (Object)(object)currentClone == (Object)null || !Object.op_Implicit((Object)(object)currentClone)) && Time.time >= graceUntil) { TryForceSkeleton(); } if (isInSkeletonForm && Time.time >= nextSoundTime) { nextSoundTime = Time.time + 120f; PlaySpawn(force: false); } } else if (isInSkeletonForm && Time.time >= graceUntil) { missingBuffStrikes++; if (missingBuffStrikes >= 3) { RestoreHumanForm(); } } } private IEnumerator F7StyleWeaponRefreshFast() { weaponCycleRunning = true; try { if (fpvActive) { ExitFpvMode(); } suppressNextSpawn = true; string handsBefore = BuildSignatureFromHumanHands(); RestoreHumanForm(); nextCheckTime = Time.time + 1f; string handsAfter = handsBefore; for (int i = 0; i < 12; i++) { ForceUpdatePlayerVisuals(); yield return null; handsAfter = BuildSignatureFromHumanHands(); if (!string.IsNullOrEmpty(handsAfter) && handsAfter != handsBefore) { Debug.Log((object)("[SkeletonMod] Hands updated frame " + (i + 1) + ": " + handsAfter)); break; } } if (string.IsNullOrEmpty(handsAfter) || handsAfter == handsBefore) { Debug.Log((object)("[SkeletonMod] Hands did not change (using whatever is on model now) before=" + handsBefore + " after=" + handsAfter)); } if (HasIllusionBuff()) { TryForceSkeleton(); } else { nextCheckTime = 0f; } } finally { weaponCycleRunning = false; } } private static bool IsGameplayWorld() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)GameData.PlayerStats == (Object)null || (Object)(object)GameData.PlayerControl == (Object)null || !((Behaviour)GameData.PlayerControl).enabled) { return false; } string text = null; try { text = GameData.SceneName; } catch { } if (string.IsNullOrEmpty(text)) { try { Scene activeScene = SceneManager.GetActiveScene(); text = ((Scene)(ref activeScene)).name; } catch { } } if (string.IsNullOrEmpty(text)) { return false; } string text2 = text.ToLowerInvariant(); return !text2.Contains("load") && !text2.Contains("char") && !text2.Contains("menu") && !text2.Contains("title") && !text2.Contains("login") && !text2.Contains("select"); } catch { return false; } } public static void PostfixAddStatusEffect(Stats __instance, Spell spell) { if ((Object)(object)__instance != (Object)(object)GameData.PlayerStats || (Object)(object)spell == (Object)null) { return; } IllusionDef illusionDef = ResolveIllusion(spell); if (illusionDef == null) { return; } if (!IsGameplayWorld()) { ApplyIllusionDef(illusionDef); RemoveOtherIllusionBuffs(illusionDef); return; } graceUntil = Time.time + 3.5f; missingBuffStrikes = 0; bool flag = isInSkeletonForm && currentFormKey == illusionDef.FormKey && (Object)(object)currentClone != (Object)null && Object.op_Implicit((Object)(object)currentClone); RemoveOtherIllusionBuffs(illusionDef); ApplyIllusionDef(illusionDef); Debug.Log((object)("[SkeletonMod] === FOUND ILLUSION: " + illusionDef.FormKey + " → " + illusionDef.PrimaryMesh + " | " + (flag ? "same-form re-click" : "full rebuild") + " ===")); if (flag) { nextSoundTime = Time.time + 120f; PlaySpawn(force: true); return; } if (fpvActive) { ExitFpvMode(); } isInSkeletonForm = false; CleanupWeapons(); if ((Object)(object)currentClone != (Object)null) { Object.Destroy((Object)(object)currentClone); currentClone = null; } suppressNextSpawn = false; TryForceSkeleton(); } public static void PostfixDamageMe(Character __instance, int _incdmg, bool _fromPlayer) { if (!isInSkeletonForm || !IsGameplayWorld() || Time.time < graceUntil || Time.time < nextAttackSfxTime || !_fromPlayer || _incdmg <= 0) { return; } try { if ((Object)(object)__instance == (Object)null || ((Object)(object)GameData.PlayerStats != (Object)null && (Object)(object)__instance == (Object)(object)GameData.PlayerStats.Myself) || ((Object)(object)GameData.PlayerControl != (Object)null && (Object)(object)((Component)__instance).gameObject == (Object)(object)((Component)GameData.PlayerControl).gameObject)) { return; } } catch { return; } if (!(Random.value > currentAttackChance)) { nextAttackSfxTime = Time.time + 0.85f; PlayAttack(); } } private static IllusionDef ResolveIllusion(Spell spell) { if ((Object)(object)spell == (Object)null) { return null; } string text = null; try { text = spell.ShapeshiftForm; } catch { } if (string.IsNullOrEmpty(text)) { return null; } text = text.Trim(); IllusionDef[] illusionList = IllusionList; foreach (IllusionDef illusionDef in illusionList) { if (string.Equals(illusionDef.FormKey, text, StringComparison.OrdinalIgnoreCase)) { return illusionDef; } } if (text.IndexOf("Skeleton", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("Knight", StringComparison.OrdinalIgnoreCase) >= 0) { return IllusionList.FirstOrDefault((IllusionDef x) => x.FormKey == "SkeletonKnight"); } if (text.IndexOf("Torment", StringComparison.OrdinalIgnoreCase) >= 0) { return IllusionList.FirstOrDefault((IllusionDef x) => x.FormKey == "TormentedSoul"); } if (text.IndexOf("Hero", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("Female", StringComparison.OrdinalIgnoreCase) >= 0) { return IllusionList.FirstOrDefault((IllusionDef x) => x.FormKey == "HeroKnightFemale"); } if (text.IndexOf("Skeleton", StringComparison.OrdinalIgnoreCase) >= 0) { return IllusionList.FirstOrDefault((IllusionDef x) => x.FormKey == "Skeleton"); } return null; } private static IllusionDef ResolveActiveIllusion() { Stats playerStats = GameData.PlayerStats; if (((playerStats != null) ? playerStats.StatusEffects : null) == null) { return null; } StatusEffect[] statusEffects = GameData.PlayerStats.StatusEffects; foreach (StatusEffect se in statusEffects) { IllusionDef illusionDef = ResolveIllusion(GetSpellFromStatusEffect(se)); if (illusionDef != null) { return illusionDef; } } return null; } private static bool HasIllusionBuff() { return ResolveActiveIllusion() != null; } private static Spell GetSpellFromStatusEffect(StatusEffect se) { if (se == null) { return null; } try { Type type = ((object)se).GetType(); FieldInfo fieldInfo = type.GetField("Effect", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("Spell", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("MySpell", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { object? value = fieldInfo.GetValue(se); return (Spell)((value is Spell) ? value : null); } object? obj = (type.GetProperty("Effect", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("Spell", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(se, null); return (Spell)((obj is Spell) ? obj : null); } catch { return null; } } private static void ApplyIllusionDef(IllusionDef def) { if (def == null) { return; } currentFormKey = def.FormKey; currentPrimaryMesh = def.PrimaryMesh; currentAttackChance = def.AttackHitChance; currentSpawnClip = null; currentAttackClip = null; if (def.SpawnWav == "Skeleton_laugh") { currentSpawnClip = skeletonLaugh; } else if (def.SpawnWav == "TormentedSpawn") { currentSpawnClip = tormentedSpawn; } else if (def.SpawnWav == "HeroFemaleSpawn") { currentSpawnClip = heroFemaleSpawn; } if (def.AttackWav == "Skeleton_Attack") { currentAttackClip = skeletonAttack; } else if (def.AttackWav == "TormentedAttack") { currentAttackClip = tormentedAttack; } else if (def.AttackWav == "HeroFemaleAttack") { currentAttackClip = heroFemaleAttack; } if (def.UseSkeletonSfx) { if ((Object)(object)currentSpawnClip == (Object)null) { currentSpawnClip = skeletonLaugh; } if ((Object)(object)currentAttackClip == (Object)null) { currentAttackClip = skeletonAttack; } } } private static void RemoveOtherIllusionBuffs(IllusionDef keep) { Stats playerStats = GameData.PlayerStats; if (((playerStats != null) ? playerStats.StatusEffects : null) == null || keep == null) { return; } try { StatusEffect[] statusEffects = GameData.PlayerStats.StatusEffects; for (int i = 0; i < statusEffects.Length; i++) { IllusionDef illusionDef = ResolveIllusion(GetSpellFromStatusEffect(statusEffects[i])); if (illusionDef != null && !(illusionDef.FormKey == keep.FormKey)) { try { GameData.PlayerStats.RemoveStatusEffect(i); } catch { } } } } catch { } } private static GameObject GetOrCacheAncientWarriorSource() { if ((Object)(object)ancientWarriorTemplateCache != (Object)null) { return ancientWarriorTemplateCache; } string[] array = new string[8] { "A Lesser Avatar of Sivakaya", "Lesser Avatar of Sivakaya", "An Apparition of Sivakaya", "Apparition of Sivakaya", "The Gardener of Loomingwood", "Gardener of Loomingwood", "Sivakayan Emissary", "SivakayanEmissary" }; GameObject[] array2 = Resources.FindObjectsOfTypeAll(); foreach (GameObject val in array2) { if ((Object)(object)val == (Object)null) { continue; } string name = ((Object)val).name; bool flag = false; string[] array3 = array; foreach (string value in array3) { if (name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { flag = true; break; } } if (!flag) { continue; } SkinnedMeshRenderer[] componentsInChildren = val.GetComponentsInChildren(true); SkinnedMeshRenderer[] array4 = componentsInChildren; foreach (SkinnedMeshRenderer val2 in array4) { if ((Object)(object)val2 != (Object)null && (((Object)((Component)val2).gameObject).name.IndexOf("Character_Ancient_Warrior_01", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)((Component)val2).gameObject).name.IndexOf("Ancient_Warrior", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)(object)val2.sharedMesh != (Object)null && ((Object)val2.sharedMesh).name != null && ((Object)val2.sharedMesh).name.IndexOf("Ancient_Warrior", StringComparison.OrdinalIgnoreCase) >= 0))) { ancientWarriorTemplateCache = val; ancientWarriorCacheSourceName = ((Object)val).name; Debug.Log((object)("[SkeletonMod] Cached Ancient Warrior template from preferred parent: " + ((Object)val).name)); return val; } } } SkinnedMeshRenderer[] array5 = Resources.FindObjectsOfTypeAll(); foreach (SkinnedMeshRenderer val3 in array5) { if ((Object)(object)val3 == (Object)null || (((Object)((Component)val3).gameObject).name.IndexOf("Character_Ancient_Warrior_01", StringComparison.OrdinalIgnoreCase) < 0 && ((Object)((Component)val3).gameObject).name.IndexOf("Ancient_Warrior", StringComparison.OrdinalIgnoreCase) < 0 && (!((Object)(object)val3.sharedMesh != (Object)null) || ((Object)val3.sharedMesh).name == null || ((Object)val3.sharedMesh).name.IndexOf("Ancient_Warrior", StringComparison.OrdinalIgnoreCase) < 0))) { continue; } Transform val4 = ((Component)val3).transform; while ((Object)(object)val4.parent != (Object)null && (Object)(object)val4.parent.parent != (Object)null) { Animator componentInChildren = ((Component)val4).GetComponentInChildren(true); Transform val5 = FindDeepChild(val4, "Hand_R") ?? FindDeepChild(val4, "Hand_L"); if ((Object)(object)componentInChildren != (Object)null || (Object)(object)val5 != (Object)null) { break; } val4 = val4.parent; } ancientWarriorTemplateCache = ((Component)val4).gameObject; ancientWarriorCacheSourceName = ((Object)((Component)val4).gameObject).name + " (mesh climb)"; Debug.Log((object)("[SkeletonMod] Cached Ancient Warrior via mesh climb: " + ancientWarriorCacheSourceName)); return ancientWarriorTemplateCache; } Debug.LogWarning((object)"[SkeletonMod] Character_Ancient_Warrior_01 not found"); return null; } private static GameObject GetOrCacheNazuraSource() { if ((Object)(object)nazuraTemplateCache != (Object)null) { return nazuraTemplateCache; } GameObject[] array = Resources.FindObjectsOfTypeAll(); foreach (GameObject val in array) { if ((Object)(object)val == (Object)null || ((Object)val).name.IndexOf("Nazura", StringComparison.OrdinalIgnoreCase) < 0) { continue; } SkinnedMeshRenderer[] componentsInChildren = val.GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && (((Object)((Component)val2).gameObject).name.IndexOf("SM_Chr_Skeleton_LightArmor_01", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)((Component)val2).gameObject).name.IndexOf("LightArmor", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)(object)val2.sharedMesh != (Object)null && ((Object)val2.sharedMesh).name != null && ((Object)val2.sharedMesh).name.IndexOf("LightArmor", StringComparison.OrdinalIgnoreCase) >= 0))) { nazuraTemplateCache = val; nazuraCacheSourceName = ((Object)val).name; Debug.Log((object)("[SkeletonMod] Cached Nazura template: " + ((Object)val).name)); return val; } } } return null; } private static void EnsureDarkLordCape(GameObject clone) { if ((Object)(object)clone == (Object)null) { return; } Transform[] componentsInChildren = clone.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val == (Object)null || (((Object)val).name.IndexOf("SM_Chr_Attach_DarkLord_Cape_01", StringComparison.OrdinalIgnoreCase) < 0 && ((Object)val).name.IndexOf("DarkLord_Cape", StringComparison.OrdinalIgnoreCase) < 0)) { continue; } ((Component)val).gameObject.SetActive(true); Renderer[] componentsInChildren2 = ((Component)val).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren2) { if ((Object)(object)val2 != (Object)null) { val2.enabled = true; } } Transform parent = val.parent; while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)clone.transform) { ((Component)parent).gameObject.SetActive(true); parent = parent.parent; } Debug.Log((object)("[SkeletonMod] Enabled existing DarkLord cape: " + ((Object)val).name)); break; } } private static void TryForceSkeleton() { //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) if (!IsGameplayWorld() || (Object)(object)GameData.PlayerStats == (Object)null) { return; } IllusionDef illusionDef = ResolveActiveIllusion(); if (illusionDef == null) { return; } ApplyIllusionDef(illusionDef); ShapeshiftMngr shapeShift = GetShapeShift(); if ((Object)(object)shapeShift == (Object)null) { return; } GameObject val = null; bool flag = string.Equals(currentFormKey, "HeroKnightFemale", StringComparison.OrdinalIgnoreCase) || string.Equals(currentPrimaryMesh, "Character_Ancient_Warrior_01", StringComparison.OrdinalIgnoreCase); bool flag2 = string.Equals(currentFormKey, "Skeleton", StringComparison.OrdinalIgnoreCase) || string.Equals(currentPrimaryMesh, "SM_Chr_Skeleton_LightArmor_01", StringComparison.OrdinalIgnoreCase); if (flag) { val = GetOrCacheAncientWarriorSource(); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)"[SkeletonMod] Ancient Warrior source missing – aborting Visage swap"); if ((Object)(object)shapeShift.PlayerRoot != (Object)null) { shapeShift.PlayerRoot.SetActive(true); } if ((Object)(object)shapeShift.CurrentModel != (Object)null) { shapeShift.CurrentModel.SetActive(true); } isInSkeletonForm = false; currentClone = null; return; } Debug.Log((object)("[SkeletonMod] Ancient Warrior source: " + ancientWarriorCacheSourceName + " | mesh: Character_Ancient_Warrior_01")); } else if (flag2) { val = GetOrCacheNazuraSource(); if ((Object)(object)val == (Object)null) { string[] array = new string[3] { "npcs/Skeleton Captain", "Skeleton Captain", "npcs/SkeletonCaptain" }; foreach (string text in array) { val = Resources.Load(text); if ((Object)(object)val != (Object)null) { break; } } } if ((Object)(object)val == (Object)null) { return; } Debug.Log((object)("[SkeletonMod] Nazura source: " + (string.IsNullOrEmpty(nazuraCacheSourceName) ? ((Object)val).name : nazuraCacheSourceName) + " | mesh: SM_Chr_Skeleton_LightArmor_01")); } else { string[] array2 = new string[3] { "npcs/Skeleton Captain", "Skeleton Captain", "npcs/SkeletonCaptain" }; foreach (string text2 in array2) { val = Resources.Load(text2); if ((Object)(object)val != (Object)null) { break; } } if ((Object)(object)val == (Object)null) { return; } Debug.Log((object)("[SkeletonMod] Bundle: Skeleton Captain | mesh: " + currentPrimaryMesh)); } GameObject val2 = Object.Instantiate(val); ((Object)val2).name = "SkeletonMod_IllusionClone"; val2.SetActive(true); object obj; if (!((Object)(object)GameData.PlayerControl != (Object)null)) { Character myChar = shapeShift.MyChar; obj = ((myChar != null) ? ((Component)myChar).transform : null); } else { obj = ((Component)GameData.PlayerControl).transform; } Transform val3 = (Transform)obj; if ((Object)(object)val3 != (Object)null) { val2.transform.SetParent(val3, false); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; } val2.transform.localScale = Vector3.one * 1f; MonoBehaviour[] componentsInChildren = val2.GetComponentsInChildren(true); foreach (MonoBehaviour val4 in componentsInChildren) { if ((Object)(object)val4 == (Object)null) { continue; } string name = ((object)val4).GetType().Name; switch (name) { default: if (!(name == "PlayerControl")) { continue; } break; case "NPC": case "Stats": case "Character": case "LootTable": case "CastSpell": case "Inventory": case "UseSkill": case "SimPlayer": break; } ((Behaviour)val4).enabled = false; } NavMeshAgent[] componentsInChildren2 = val2.GetComponentsInChildren(true); foreach (NavMeshAgent val5 in componentsInChildren2) { ((Behaviour)val5).enabled = false; } Collider[] componentsInChildren3 = val2.GetComponentsInChildren(true); foreach (Collider val6 in componentsInChildren3) { val6.enabled = false; } SkinnedMeshRenderer[] componentsInChildren4 = val2.GetComponentsInChildren(true); SkinnedMeshRenderer val7 = null; SkinnedMeshRenderer[] array3 = componentsInChildren4; foreach (SkinnedMeshRenderer val8 in array3) { if (!((Object)(object)((val8 != null) ? val8.sharedMesh : null) == (Object)null) && (((Object)((Component)val8).gameObject).name.IndexOf(currentPrimaryMesh, StringComparison.OrdinalIgnoreCase) >= 0 || (((Object)val8.sharedMesh).name != null && ((Object)val8.sharedMesh).name.IndexOf(currentPrimaryMesh, StringComparison.OrdinalIgnoreCase) >= 0))) { val7 = val8; break; } } if ((Object)(object)val7 == (Object)null && illusionDef.FallbackMeshes != null) { string[] fallbackMeshes = illusionDef.FallbackMeshes; foreach (string value in fallbackMeshes) { SkinnedMeshRenderer[] array4 = componentsInChildren4; foreach (SkinnedMeshRenderer val9 in array4) { if (!((Object)(object)val9 == (Object)null) && (((Object)((Component)val9).gameObject).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)(object)val9.sharedMesh != (Object)null && ((Object)val9.sharedMesh).name != null && ((Object)val9.sharedMesh).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0))) { val7 = val9; break; } } if ((Object)(object)val7 != (Object)null) { break; } } } if ((Object)(object)val7 == (Object)null && componentsInChildren4.Length != 0) { val7 = componentsInChildren4[0]; } SkinnedMeshRenderer[] array5 = componentsInChildren4; foreach (SkinnedMeshRenderer val10 in array5) { if ((Object)(object)val10 != (Object)null) { ((Component)val10).gameObject.SetActive((Object)(object)val10 == (Object)(object)val7); } } if ((Object)(object)val7 != (Object)null) { ((Component)val7).gameObject.SetActive(true); Transform val11 = ((Component)val7).transform; while ((Object)(object)val11 != (Object)null && (Object)(object)val11 != (Object)(object)val2.transform.parent) { ((Component)val11).gameObject.SetActive(true); val11 = val11.parent; } Debug.Log((object)("[SkeletonMod] Keeping mesh: " + ((Object)((Component)val7).gameObject).name)); } if (flag2) { EnsureDarkLordCape(val2); } if ((Object)(object)shapeShift.CurrentModel != (Object)null) { shapeShift.CurrentModel.SetActive(false); } shapeShift.CurrentModel = val2; if ((Object)(object)shapeShift.PlayerRoot != (Object)null) { shapeShift.PlayerRoot.SetActive(false); } Animator componentInChildren = val2.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)shapeShift.MyChar != (Object)null) { shapeShift.MyChar.AssignAnim(componentInChildren); typeof(ShapeshiftMngr).GetMethod("RebindAnim", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(shapeShift, null); } currentClone = val2; isInSkeletonForm = true; missingBuffStrikes = 0; graceUntil = Time.time + 0.6f; nextCheckTime = Time.time + 0.35f; nextSoundTime = Time.time + 120f; nextAttackSfxTime = Time.time + 0.5f; weaponCycleCooldownUntil = Time.time + 0.85f; pendingF7Cycle = false; fpvActive = false; AttachPlayerWeapons(val2); lastEquipSig = BuildEquipSignature(); bool flag3 = !suppressNextSpawn; suppressNextSpawn = false; if (flag3) { PlaySpawn(force: true); } Debug.Log((object)("[SkeletonMod] Swapped to " + (((Object)(object)val7 != (Object)null) ? ((Object)((Component)val7).gameObject).name : currentPrimaryMesh) + " + weapons" + (flag3 ? "" : " (silent re-click)"))); } private static void RestoreHumanForm() { if ((Object)(object)GameData.PlayerStats == (Object)null) { return; } ClearFpvState(); ShapeshiftMngr shapeShift = GetShapeShift(); CleanupWeapons(); if ((Object)(object)currentClone != (Object)null) { Object.Destroy((Object)(object)currentClone); currentClone = null; } if ((Object)(object)shapeShift != (Object)null) { try { shapeShift.SwapToHuman(); } catch { } if ((Object)(object)shapeShift.PlayerRoot != (Object)null) { shapeShift.PlayerRoot.SetActive(true); } } isInSkeletonForm = false; missingBuffStrikes = 0; lastSpawnFormKey = ""; ForceUpdatePlayerVisuals(); Debug.Log((object)"[SkeletonMod] Forced player visual refresh"); Debug.Log((object)"[SkeletonMod] Restored human form"); } private static void CleanupWeapons() { foreach (GameObject attachedWeapon in attachedWeapons) { if ((Object)(object)attachedWeapon != (Object)null) { Object.Destroy((Object)(object)attachedWeapon); } } attachedWeapons.Clear(); } private static Transform FindDeepChild(Transform parent, string name) { if ((Object)(object)parent == (Object)null) { return null; } if (((Object)parent).name == name) { return parent; } for (int i = 0; i < parent.childCount; i++) { Transform val = FindDeepChild(parent.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Transform GetHumanRoot() { try { ShapeshiftMngr shapeShift = GetShapeShift(); if ((Object)(object)shapeShift?.PlayerRoot != (Object)null) { return shapeShift.PlayerRoot.transform; } PlayerControl playerControl = GameData.PlayerControl; return (playerControl != null) ? ((Component)playerControl).transform : null; } catch { return null; } } private static void AttachPlayerWeapons(GameObject skeletonRoot) { if ((Object)(object)skeletonRoot == (Object)null) { return; } Transform humanRoot = GetHumanRoot(); if (!((Object)(object)humanRoot == (Object)null)) { Transform val = FindDeepChild(skeletonRoot.transform, "Hand_R") ?? FindDeepChild(skeletonRoot.transform, "hand_r"); Transform val2 = FindDeepChild(skeletonRoot.transform, "Hand_L") ?? FindDeepChild(skeletonRoot.transform, "hand_l"); Transform val3 = FindDeepChild(humanRoot, "Hand_R") ?? FindDeepChild(humanRoot, "hand_r"); Transform val4 = FindDeepChild(humanRoot, "Hand_L") ?? FindDeepChild(humanRoot, "hand_l"); int num = 0; if ((Object)(object)val3 != (Object)null && (Object)(object)val != (Object)null) { num += CloneActiveWeaponMeshes(val3, val, "Right"); } if ((Object)(object)val4 != (Object)null && (Object)(object)val2 != (Object)null) { num += CloneActiveWeaponMeshes(val4, val2, "Left"); } Debug.Log((object)("[SkeletonMod][Weapons] Total: " + num)); } } private static bool IsVfxRelatedTypeName(string n) { if (string.IsNullOrEmpty(n)) { return false; } return n.IndexOf("Particle", StringComparison.OrdinalIgnoreCase) >= 0 || n.IndexOf("Trail", StringComparison.OrdinalIgnoreCase) >= 0 || n.IndexOf("VFX", StringComparison.OrdinalIgnoreCase) >= 0 || n.IndexOf("Effect", StringComparison.OrdinalIgnoreCase) >= 0 || n.IndexOf("FX", StringComparison.OrdinalIgnoreCase) >= 0; } private static int CloneActiveWeaponMeshes(Transform humanHand, Transform skelHand, string side) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) int num = 0; if ((Object)(object)humanHand == (Object)null || (Object)(object)skelHand == (Object)null) { return 0; } bool flag = string.Equals(currentFormKey, "HeroKnightFemale", StringComparison.OrdinalIgnoreCase) || string.Equals(currentPrimaryMesh, "Character_Ancient_Warrior_01", StringComparison.OrdinalIgnoreCase); bool flag2 = string.Equals(currentFormKey, "Skeleton", StringComparison.OrdinalIgnoreCase) || string.Equals(currentPrimaryMesh, "SM_Chr_Skeleton_LightArmor_01", StringComparison.OrdinalIgnoreCase); List list = new List(); Transform val = humanHand; while ((Object)(object)val != (Object)null) { if (!((Component)val).gameObject.activeSelf) { list.Add(((Component)val).gameObject); ((Component)val).gameObject.SetActive(true); } val = val.parent; } foreach (Transform item in humanHand) { Transform val2 = item; if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeSelf) { continue; } string text = ((Object)val2).name.ToLowerInvariant(); if (text.Contains("hand") || text.Contains("finger") || text.Contains("wrist") || ((Object)(object)((Component)val2).GetComponentInChildren(true) == (Object)null && (Object)(object)((Component)val2).GetComponentInChildren(true) == (Object)null)) { continue; } GameObject val3 = Object.Instantiate(((Component)val2).gameObject, skelHand); ((Object)val3).name = ((Object)val2).name; val3.SetActive(true); if (flag || flag2) { Vector3 localPosition = ((side == "Right") ? ANCIENT_WARRIOR_OFFSET_RIGHT : ANCIENT_WARRIOR_OFFSET_LEFT); val3.transform.localPosition = localPosition; val3.transform.localRotation = val2.localRotation; val3.transform.localScale = val2.localScale * 0.01f; } else { val3.transform.localPosition = val2.localPosition; val3.transform.localRotation = val2.localRotation; val3.transform.localScale = val2.localScale; } Renderer[] componentsInChildren = val3.GetComponentsInChildren(true); foreach (Renderer val4 in componentsInChildren) { if ((Object)(object)val4 != (Object)null) { val4.enabled = true; } } MonoBehaviour[] componentsInChildren2 = val3.GetComponentsInChildren(true); foreach (MonoBehaviour val5 in componentsInChildren2) { if (!((Object)(object)val5 == (Object)null) && !IsVfxRelatedTypeName(((object)val5).GetType().Name)) { ((Behaviour)val5).enabled = false; } } ParticleSystem[] componentsInChildren3 = val3.GetComponentsInChildren(true); foreach (ParticleSystem val6 in componentsInChildren3) { if ((Object)(object)val6 != (Object)null && !val6.isPlaying) { val6.Play(true); } } TrailRenderer[] componentsInChildren4 = val3.GetComponentsInChildren(true); foreach (TrailRenderer val7 in componentsInChildren4) { if (!((Object)(object)val7 == (Object)null)) { ((Renderer)val7).enabled = true; val7.Clear(); } } LineRenderer[] componentsInChildren5 = val3.GetComponentsInChildren(true); foreach (LineRenderer val8 in componentsInChildren5) { if ((Object)(object)val8 != (Object)null) { ((Renderer)val8).enabled = true; } } attachedWeapons.Add(val3); num++; Debug.Log((object)("[SkeletonMod][Weapons] Attached " + side + ": " + ((Object)val2).name + ((flag || flag2) ? " (scale 0.01 + Anubis offsets)" : ""))); } foreach (GameObject item2 in list) { if ((Object)(object)item2 != (Object)null) { item2.SetActive(false); } } return num; } private static void EnsureSfxSource() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)sfxSource != (Object)null)) { GameObject val = new GameObject("SkeletonMod_SFX"); Object.DontDestroyOnLoad((Object)(object)val); sfxSource = val.AddComponent(); sfxSource.playOnAwake = false; sfxSource.spatialBlend = 0f; sfxSource.volume = 1f; } } private static void TryLoadSounds() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); skeletonLaugh = LoadWavFromDir(directoryName, "Skeleton_laugh"); skeletonAttack = LoadWavFromDir(directoryName, "Skeleton_Attack"); tormentedSpawn = LoadWavFromDir(directoryName, "TormentedSpawn"); tormentedAttack = LoadWavFromDir(directoryName, "TormentedAttack"); heroFemaleSpawn = LoadWavFromDir(directoryName, "HeroFemaleSpawn"); heroFemaleAttack = LoadWavFromDir(directoryName, "HeroFemaleAttack"); dingClip = LoadWavFromDir(directoryName, "EQ_DING"); Debug.Log((object)"[SkeletonMod] Sounds loaded"); } private static AudioClip LoadWavFromDir(string dir, string baseName) { if (string.IsNullOrEmpty(dir)) { return null; } string[] array = new string[2] { Path.Combine(dir, baseName + ".wav"), Path.Combine(dir, baseName) }; foreach (string path in array) { if (File.Exists(path)) { AudioClip val = LoadWavFile(path); if ((Object)(object)val != (Object)null) { ((Object)val).name = baseName; Debug.Log((object)("[SkeletonMod] WAV loaded: " + baseName)); return val; } } } return null; } private static AudioClip LoadWavFile(string path) { try { byte[] array = File.ReadAllBytes(path); if (array.Length < 44 || array[0] != 82) { return null; } int num = BitConverter.ToInt16(array, 22); int num2 = BitConverter.ToInt32(array, 24); int num3 = BitConverter.ToInt16(array, 34); int num4 = BitConverter.ToInt16(array, 20); int i = 12; int num5 = 0; int num6; for (; i + 8 < array.Length; i += 8 + num6) { string text = Encoding.ASCII.GetString(array, i, 4); num6 = BitConverter.ToInt32(array, i + 4); if (text == "data") { i += 8; num5 = num6; break; } } if (num5 <= 0) { return null; } int num7; float[] array2; if (num4 == 1 && num3 == 16) { num7 = num5 / 2; array2 = new float[num7]; for (int j = 0; j < num7; j++) { array2[j] = (float)BitConverter.ToInt16(array, i + j * 2) / 32768f; } } else { if (num4 != 1 || num3 != 8) { return null; } num7 = num5; array2 = new float[num7]; for (int k = 0; k < num7; k++) { array2[k] = (float)(array[i + k] - 128) / 128f; } } AudioClip val = AudioClip.Create(Path.GetFileNameWithoutExtension(path), num7 / Mathf.Max(1, num), num, num2, false); val.SetData(array2, 0); return val; } catch { return null; } } private static void PlayClip(AudioClip clip, float vol = 1f) { if (!((Object)(object)clip == (Object)null)) { EnsureSfxSource(); if ((Object)(object)sfxSource != (Object)null) { sfxSource.PlayOneShot(clip, vol); Debug.Log((object)("[SkeletonMod] *sound* " + ((Object)clip).name)); } } } private static void PlaySpawn(bool force) { if (IsGameplayWorld() && (!(Time.time < spawnSfxReadyAt) || force)) { PlayClip(currentSpawnClip ?? skeletonLaugh); lastSpawnFormKey = currentFormKey; } } private static void PlayAttack() { if (IsGameplayWorld()) { PlayClip(currentAttackClip, 0.9f); } } private static void CheckLevelUpDing() { if ((Object)(object)GameData.PlayerStats == (Object)null) { return; } int level = GameData.PlayerStats.Level; if (lastKnownLevel < 0) { lastKnownLevel = level; } else if (level > lastKnownLevel) { int num = level - lastKnownLevel; lastKnownLevel = level; if (num <= 3 && IsGameplayWorld()) { PlayClip(dingClip); } } else if (level < lastKnownLevel) { lastKnownLevel = level; } } }