using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using UnityEngine; using UnityEngine.AI; using UnityEngine.EventSystems; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; using Utilities; using YAPYAP; using YAPYAP.Npc.Frog; using YAPYAP.Npc.Shopkeeper; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("YAPYAP Expanded")] [assembly: AssemblyDescription("YAPYAP Expanded Beta 1")] [assembly: AssemblyFileVersion("0.13.0.0")] [assembly: AssemblyVersion("0.13.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace YAPYAPExpanded { internal static class AssetLoader { internal static AssetBundle Bundle { get; private set; } internal static GameObject ChaosVisual { get; private set; } internal static GameObject FrostVisual { get; private set; } internal static void Load() { string text = Path.Combine(Paths.PluginPath, "YAPYAPExpanded", "yapyapexpanded"); if (!File.Exists(text)) { Plugin.Log.LogError((object)("AssetBundle not found: " + text)); return; } Bundle = AssetBundle.LoadFromFile(text); if ((Object)(object)Bundle == (Object)null) { Plugin.Log.LogError((object)"AssetBundle.LoadFromFile returned null"); return; } Plugin.Log.LogInfo((object)"AssetBundle loaded"); string[] allAssetNames = Bundle.GetAllAssetNames(); string[] array = allAssetNames; foreach (string text2 in array) { Plugin.Log.LogInfo((object)("Asset: " + text2)); } ChaosVisual = LoadPrefabByEnding(allAssetNames, "/haos.prefab"); FrostVisual = LoadPrefabByEnding(allAssetNames, "/frost.prefab"); Plugin.Log.LogInfo((object)("Chaos visual: " + (((Object)(object)ChaosVisual != (Object)null) ? ((Object)ChaosVisual).name : "NOT FOUND"))); Plugin.Log.LogInfo((object)("Frost visual: " + (((Object)(object)FrostVisual != (Object)null) ? ((Object)FrostVisual).name : "NOT FOUND"))); } private static GameObject LoadPrefabByEnding(string[] names, string ending) { foreach (string text in names) { if (text.EndsWith(ending, StringComparison.OrdinalIgnoreCase)) { return Bundle.LoadAsset(text); } } return null; } } internal static class ChaosRollSync { internal static Quaternion Encode(int face) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (face < 1 || face > 6) { throw new ArgumentOutOfRangeException("face"); } double num = (double)face * Math.PI / 12.0; return new Quaternion(0f, (float)Math.Sin(num), 0f, (float)Math.Cos(num)); } internal static int Decode(Quaternion rotation) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) double num = Math.Atan2(rotation.y, rotation.w) * 12.0 / Math.PI; int num2 = (int)Math.Round(num); if (num2 < 1 || num2 > 6 || !(Math.Abs(num - (double)num2) < 0.01)) { return 0; } return num2; } internal static void Receive(Spell spell, Quaternion payload) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) int num = Decode(payload); if (num != 0 && !((Object)(object)spell.CasterIdentity == (Object)null) && spell.CasterIdentity.isLocalPlayer) { RollOverlay.ShowRoll(num); } } } internal struct UpgradeRequest : NetworkMessage { internal uint Merchant; internal uint Token; internal int Kind; internal int Expected; } internal struct UpgradeState : NetworkMessage { internal uint Pawn; internal uint Token; internal int Hp; internal int Speed; internal int Inventory; internal bool Open; internal string Result; } internal sealed class CharacterUpgrades : MonoBehaviour { private static readonly Dictionary Clients = new Dictionary(); private static readonly Dictionary LastRequest = new Dictionary(); internal static bool Ready; private bool serverRegistered; private bool clientRegistered; private double nextSync; internal static void Install(Harmony harmony) { Ready = false; try { UpgradeInventory.Install(harmony); InstallCodecs(); Ready = true; } catch (Exception ex) { harmony.UnpatchSelf(); Plugin.Log.LogError((object)("Upgrade system unavailable: " + ex)); } } internal static void InstallCodecs() { Writer.write = delegate(NetworkWriter w, UpgradeRequest m) { NetworkWriterExtensions.WriteUInt(w, m.Merchant); NetworkWriterExtensions.WriteUInt(w, m.Token); NetworkWriterExtensions.WriteInt(w, m.Kind); NetworkWriterExtensions.WriteInt(w, m.Expected); }; Reader.read = (NetworkReader r) => new UpgradeRequest { Merchant = NetworkReaderExtensions.ReadUInt(r), Token = NetworkReaderExtensions.ReadUInt(r), Kind = NetworkReaderExtensions.ReadInt(r), Expected = NetworkReaderExtensions.ReadInt(r) }; Writer.write = delegate(NetworkWriter w, UpgradeState m) { NetworkWriterExtensions.WriteUInt(w, m.Pawn); NetworkWriterExtensions.WriteUInt(w, m.Token); NetworkWriterExtensions.WriteInt(w, m.Hp); NetworkWriterExtensions.WriteInt(w, m.Speed); NetworkWriterExtensions.WriteInt(w, m.Inventory); NetworkWriterExtensions.WriteBool(w, m.Open); NetworkWriterExtensions.WriteString(w, m.Result); }; Reader.read = (NetworkReader r) => new UpgradeState { Pawn = NetworkReaderExtensions.ReadUInt(r), Token = NetworkReaderExtensions.ReadUInt(r), Hp = NetworkReaderExtensions.ReadInt(r), Speed = NetworkReaderExtensions.ReadInt(r), Inventory = NetworkReaderExtensions.ReadInt(r), Open = NetworkReaderExtensions.ReadBool(r), Result = NetworkReaderExtensions.ReadString(r) }; } internal static string Key(Pawn pawn, int kind) { return "PLAYER." + pawn.PlayerId + ".YAPYAPEXP.UPGRADE." + kind; } internal static UpgradeLevels Levels(Pawn pawn) { if ((Object)(object)pawn == (Object)null) { return default(UpgradeLevels); } if (NetworkServer.active) { UpgradeLevels result = default(UpgradeLevels); SaveManager val = default(SaveManager); if (!string.IsNullOrEmpty(pawn.PlayerId) && Service.Get(ref val)) { val.TryGetInt(Key(pawn, 0), ref result.Hp); val.TryGetInt(Key(pawn, 1), ref result.Speed); val.TryGetInt(Key(pawn, 2), ref result.Inventory); result.Hp = UpgradeRules.Clamp(0, result.Hp); result.Speed = UpgradeRules.Clamp(1, result.Speed); result.Inventory = UpgradeRules.Clamp(2, result.Inventory); } return result; } if (!Clients.TryGetValue(((NetworkBehaviour)pawn).netId, out var value)) { return default(UpgradeLevels); } return value; } internal static bool MerchantValid(Pawn pawn, uint merchantId, out ShopkeeperStateMachine merchant) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) merchant = null; Dictionary dictionary = (NetworkServer.active ? NetworkServer.spawned : NetworkClient.spawned); if ((Object)(object)pawn == (Object)null || pawn.IsDead || pawn.IsExtracted || !dictionary.TryGetValue(merchantId, out var value)) { return false; } merchant = ((Component)value).GetComponentInChildren(true); if ((Object)(object)merchant == (Object)null || !((Behaviour)merchant).isActiveAndEnabled || (Object)(object)merchant._npcBehaviour == (Object)null || merchant._npcBehaviour.IsKilled) { return false; } object? value2 = AccessTools.Field(typeof(ShopkeeperStateMachine), "_shop").GetValue(merchant); Shop val = (Shop)((value2 is Shop) ? value2 : null); if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { Vector3 val2 = ((Component)pawn).transform.position - ((Component)merchant).transform.position; if (!(((Vector3)(ref val2)).sqrMagnitude > 16f)) { object? value3 = AccessTools.Field(typeof(ShopkeeperStateMachine), "_collider").GetValue(merchant); Collider val3 = (Collider)((value3 is Collider) ? value3 : null); ? val4; if (!((Object)(object)val3 != (Object)null)) { val4 = ((Component)merchant).transform.position + Vector3.up; } else { Bounds bounds = val3.bounds; float x = ((Bounds)(ref bounds)).center.x; bounds = val3.bounds; float num = ((Bounds)(ref bounds)).max.y - 0.15f; bounds = val3.bounds; val4 = new Vector3(x, num, ((Bounds)(ref bounds)).center.z); } Vector3 val5 = (Vector3)val4; Vector3 lookOrigin = pawn.LookOrigin; val2 = val5 - pawn.LookOrigin; Vector3 normalized = ((Vector3)(ref val2)).normalized; val2 = val5 - pawn.LookOrigin; foreach (RaycastHit item in from val6 in Physics.RaycastAll(lookOrigin, normalized, ((Vector3)(ref val2)).magnitude, -1, (QueryTriggerInteraction)1) orderby ((RaycastHit)(ref val6)).distance select val6) { RaycastHit current = item; NetworkIdentity componentInParent = ((Component)((RaycastHit)(ref current)).collider).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)(object)((NetworkBehaviour)pawn).netIdentity)) { if ((Object)(object)componentInParent == (Object)(object)value) { return true; } if ((Object)(object)((RaycastHit)(ref current)).collider.attachedRigidbody == (Object)null) { return false; } } } return true; } } return false; } private void Update() { if (!Ready) { return; } if (NetworkServer.active && !serverRegistered) { NetworkServer.RegisterHandler((Action)Purchase, true); serverRegistered = true; } if (!NetworkServer.active && serverRegistered) { serverRegistered = false; LastRequest.Clear(); nextSync = 0.0; } if (NetworkClient.active && !clientRegistered) { NetworkClient.RegisterHandler((Action)Receive, true); clientRegistered = true; } if (!NetworkClient.active && clientRegistered) { clientRegistered = false; Clients.Clear(); } if (!NetworkServer.active || !(NetworkTime.time >= nextSync)) { return; } nextSync = NetworkTime.time + 1.0; foreach (NetworkConnectionToClient value in NetworkServer.connections.Values) { Pawn val = (((Object)(object)((value != null) ? ((NetworkConnection)value).identity : null) != (Object)null) ? ((Component)((NetworkConnection)value).identity).GetComponent() : null); if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.PlayerId)) { EnsureSlots(val); NetworkServer.SendToAll(State(val, 0u, open: false, ""), 0, false); } } } internal static void EnsureSlots(Pawn pawn) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active && !((Object)(object)((pawn != null) ? pawn.Inventory : null) == (Object)null)) { int num = UpgradeRules.Capacity(Levels(pawn).Inventory); while (pawn.Inventory.Items.Count < num) { pawn.Inventory.Items.Add(InventoryItem.Empty); } } } private static UpgradeState State(Pawn pawn, uint token, bool open, string result) { UpgradeLevels upgradeLevels = Levels(pawn); return new UpgradeState { Pawn = ((NetworkBehaviour)pawn).netId, Token = token, Hp = upgradeLevels.Hp, Speed = upgradeLevels.Speed, Inventory = upgradeLevels.Inventory, Open = open, Result = result }; } private static void Purchase(NetworkConnectionToClient connection, UpgradeRequest request) { //IL_050b: Unknown result type (might be due to invalid IL or missing references) //IL_0510: Unknown result type (might be due to invalid IL or missing references) if (!Ready) { return; } NetworkConnectionToClient obj = connection; if ((Object)(object)((obj != null) ? ((NetworkConnection)obj).identity : null) == (Object)null) { return; } Pawn pawn = ((Component)((NetworkConnection)connection).identity).GetComponent(); if ((Object)(object)pawn == (Object)null) { return; } if (LastRequest.TryGetValue(connection.connectionId, out var value) && NetworkTime.time - value < 0.15) { Reply("error.wait"); return; } LastRequest[connection.connectionId] = NetworkTime.time; if (!MerchantValid(pawn, request.Merchant, out var _)) { Reply("error.merchant"); return; } SaveManager val = default(SaveManager); if (string.IsNullOrEmpty(pawn.PlayerId) || !Service.Get(ref val) || !(bool)AccessTools.Method(typeof(SaveManager), "IsSlotValid", (Type[])null, (Type[])null).Invoke(val, null)) { Reply("error.save"); return; } if (request.Kind == -1) { Reply("", open: true); return; } if (!UpgradeRules.ValidKind(request.Kind) || (Object)(object)GameManager.Instance == (Object)null) { Reply("error.kind"); return; } int num = Levels(pawn).Get(request.Kind); int gold = GameManager.Instance.Gold; int num2 = UpgradeRules.Price(request.Kind, num); if (!UpgradeRules.CanBuy(request.Kind, num, request.Expected, gold)) { Reply((num2 < 0) ? "error.max" : ((num != request.Expected) ? "error.stale" : "error.gold")); return; } if ((request.Kind == 0 && (Object)(object)pawn.Hurtbox == (Object)null) || (request.Kind == 2 && (Object)(object)pawn.Inventory == (Object)null)) { Reply("error.pawn"); return; } int network_maxHealth = (((Object)(object)pawn.Hurtbox != (Object)null) ? pawn.Hurtbox.MaxHealth : 0); int num3 = (((Object)(object)pawn.Hurtbox != (Object)null) ? pawn.Hurtbox.Health : 0); PawnInventory inventory = pawn.Inventory; int num4 = ((inventory != null) ? inventory.Items.Count : 0); try { GameManager.Instance.ModifyGold(-num2); val.SetInt(Key(pawn, request.Kind), num + 1); if (request.Kind == 0) { pawn.Hurtbox.SvModifyMaxHp(10); pawn.Hurtbox.SvPersistMaxHp(); } if (request.Kind == 2) { EnsureSlots(pawn); } val.SetInt("GAME.GOLD", GameManager.Instance.Gold); val.WriteCurrent(); NetworkServer.SendToAll(State(pawn, 0u, open: false, ""), 0, false); Reply("upgrade.success"); Plugin.Log.LogInfo((object)("UPGRADE " + pawn.PlayerId + " kind=" + request.Kind + " level=" + (num + 1) + " price=" + num2)); } catch (Exception ex) { val.SetInt(Key(pawn, request.Kind), num); GameManager.Instance.ModifyGold(num2); val.SetInt("GAME.GOLD", GameManager.Instance.Gold); if (request.Kind == 0 && (Object)(object)pawn.Hurtbox != (Object)null) { pawn.Hurtbox.Network_maxHealth = network_maxHealth; pawn.Hurtbox.SvSetHealth(num3); pawn.Hurtbox.SvPersistMaxHp(); } if (request.Kind == 2 && (Object)(object)pawn.Inventory != (Object)null) { while (pawn.Inventory.Items.Count > num4) { InventoryItem val2 = pawn.Inventory.Items[pawn.Inventory.Items.Count - 1]; if (!((InventoryItem)(ref val2)).IsEmpty) { break; } pawn.Inventory.Items.RemoveAt(pawn.Inventory.Items.Count - 1); } } Reply("error.purchase"); Plugin.Log.LogError((object)("Upgrade purchase rolled back: " + ex)); } void Reply(string result, bool open = false) { ((NetworkConnection)connection).Send(State(pawn, request.Token, open, result), 0); } } private static void Receive(UpgradeState state) { Clients[state.Pawn] = new UpgradeLevels { Hp = UpgradeRules.Clamp(0, state.Hp), Speed = UpgradeRules.Clamp(1, state.Speed), Inventory = UpgradeRules.Clamp(2, state.Inventory) }; UpgradeMenu.Receive(state); } } internal static class CustomSpellPatcher { internal static void Install(Harmony harmony) { //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Expected O, but got Unknown CustomSpellSystem.Ready = false; string text = "Spell base reverse patches"; try { SpellVanilla.Install(harmony); Dictionary dictionary = new Dictionary { { "OnSpellActivate", "Activate" }, { "CastSpell", "Activate" }, { "OnSpellDeactivate", "Stop" }, { "StopSpell", "Stop" }, { "Initialize", "Initialize" }, { "CanCast", "CanCast" }, { "Update", "Update" }, { "SetCastData", "SetCastData" }, { "SetWandHeld", "SetWandHeld" }, { "get_CooldownProgress", "CooldownReady" }, { "get_IsInstantCast", "Instant" }, { "get_IsCasting", "IsCasting" }, { "get_SpellName", "Name" }, { "get_ChargeableName", "Name" }, { "OnCasterIdentityChanged", "CasterChanged" }, { "OnCurrentChargesChanged", "ChargesChanged" }, { "OnIsCastingChanged", "CastingChanged" }, { "OnCastTimeChanged", "CastTimeChanged" }, { "GetSpawnPositionRotation", "SpawnPose" }, { "UserCode_RpcPlayEffect__SpellEffectType__Vector3__Quaternion", "Effect" }, { "FixedUpdate", "Skip" }, { "LateUpdate", "Skip" }, { "ClCastSpell", "Skip" }, { "ClStopSpell", "Skip" }, { "OnPickedUpWandsChanged", "Skip" }, { "OnRegenerationStartTimeChanged", "Skip" } }; Type[] types; try { types = typeof(Spell).Assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types; } int num = 0; foreach (MethodInfo patchCandidate in GetPatchCandidates(types)) { if (dictionary.TryGetValue(patchCandidate.Name, out var value)) { text = patchCandidate.DeclaringType.FullName + "." + patchCandidate.Name; MethodInfo method = typeof(CustomSpellPatcher).GetMethod(value, BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)patchCandidate, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } } CustomSpellSystem.Ready = true; Plugin.Log.LogInfo((object)("Custom spell lifecycle hooks: " + num)); } catch (Exception ex2) { Plugin.Log.LogError((object)("Spell API incompatible at " + text + "; custom wand spawning disabled: " + ex2)); } } internal static IEnumerable GetPatchCandidates(IEnumerable types) { HashSet visited = new HashSet(); foreach (Type type2 in types) { if (type2 == null || type2.ContainsGenericParameters || !typeof(Spell).IsAssignableFrom(type2)) { continue; } Type type = type2; while (type != null && typeof(Spell).IsAssignableFrom(type)) { if (!type.ContainsGenericParameters && visited.Add(type)) { MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!methodInfo.IsAbstract && !methodInfo.ContainsGenericParameters) { yield return methodInfo; } } } type = type.BaseType; } } } private static bool Skip(Spell __instance) { return !CustomSpellSystem.IsManagedChild(__instance); } private static bool Activate(Spell __instance) { if (Skip(__instance)) { return true; } CustomSpellSystem.Activate(__instance); return false; } private static bool Stop(Spell __instance) { if (Skip(__instance)) { return true; } if (NetworkServer.active && __instance.NetworkisCasting) { SpellVanilla.Deactivate(__instance); } return false; } private static bool Initialize(Spell __instance, NetworkIdentity __0) { if (Skip(__instance)) { return true; } SpellVanilla.Initialize(__instance, __0); return false; } private static bool CanCast(Spell __instance, ref bool __result) { if (Skip(__instance)) { return true; } __result = CustomSpellSystem.Definition(__instance) != null && CustomSpellSystem.IsHeld(__instance) && SpellVanilla.CanCast(__instance); return false; } private static bool Update(Spell __instance) { if (Skip(__instance)) { return true; } SpellVanilla.Update(__instance); return false; } private static bool SetCastData(Spell __instance) { if (Skip(__instance)) { return true; } if (NetworkServer.active) { SpellVanilla.SetCastData(__instance); } return false; } private static bool SetWandHeld(Spell __instance, bool __0) { if (Skip(__instance)) { return true; } SpellVanilla.SetWandHeld(__instance, __0); return false; } private static bool CooldownReady(Spell __instance, ref float __result) { if (Skip(__instance)) { return true; } __result = 1f; return false; } private static bool Instant(Spell __instance, ref bool __result) { if (Skip(__instance)) { return true; } __result = true; return false; } private static bool IsCasting(Spell __instance, ref bool __result) { if (Skip(__instance)) { return true; } __result = __instance.NetworkisCasting; return false; } private static bool Name(Spell __instance, ref string __result) { if (Skip(__instance)) { return true; } SpellDefinition spellDefinition = CustomSpellSystem.Definition(__instance); __result = ((spellDefinition == null) ? "" : spellDefinition.LocalName); return false; } private static bool CasterChanged(Spell __instance, NetworkIdentity __0, NetworkIdentity __1) { if (Skip(__instance)) { return true; } SpellVanilla.CasterChanged(__instance, __0, __1); return false; } private static bool ChargesChanged(Spell __instance, int __0, int __1) { if (Skip(__instance)) { return true; } SpellVanilla.ChargesChanged(__instance, __0, __1); return false; } private static bool CastingChanged(Spell __instance, bool __0, bool __1) { if (Skip(__instance)) { return true; } SpellVanilla.CastingChanged(__instance, __0, __1); return false; } private static bool CastTimeChanged(Spell __instance, double __0, double __1) { return Skip(__instance); } private static bool SpawnPose(Spell __instance, ref Vector3 __0, ref Quaternion __1) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (Skip(__instance)) { return true; } SpellTargets.Aim(__instance, out __0, out var direction); __1 = Quaternion.LookRotation(direction); return false; } private static bool Effect(Spell __instance, SpellEffectType __0, Vector3 __1, Quaternion __2) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (Skip(__instance)) { return true; } SpellDefinition spellDefinition = CustomSpellSystem.Definition(__instance); if (spellDefinition != null) { if (spellDefinition.Id == SpellId.ChaosRoll && (int)__0 == 3) { ChaosRollSync.Receive(__instance, __2); __2 = Quaternion.identity; } SpellVisuals.Play(__instance, spellDefinition, __0, __1); SpellVanilla.ClientEffect(__instance, __0, __1, __2); } return false; } } internal static class CustomSpellSystem { private static readonly BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static readonly FieldInfo SpellDataField = typeof(Spell).GetField("spellData", Fields); private static readonly FieldInfo SecretField = typeof(Spell).GetField("isSecret", Fields); private static readonly FieldInfo VoiceSpellsField = typeof(VoiceSpell).GetField("spells", Fields); internal static bool Ready; private static readonly Random DiceRandom = new Random(); internal static bool CanConfigure(GameObject root) { return GetChildren(root).Count >= 4; } private static List GetChildren(GameObject root) { List list = new List(); if ((Object)(object)root == (Object)null || VoiceSpellsField == null) { return list; } NetworkPuppetWandProp componentInChildren = root.GetComponentInChildren(true); VoiceSpell val = (VoiceSpell)(((Object)(object)componentInChildren != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null) { return list; } if (!(VoiceSpellsField.GetValue(val) is Spell[] array)) { return list; } Spell[] array2 = array; foreach (Spell val2 in array2) { if ((Object)(object)val2 != (Object)null && !(val2 is VoiceSpell) && (Object)(object)val2.SpellData != (Object)null && !list.Contains(val2)) { list.Add(val2); } } return list; } internal static bool ConfigureWand(GameObject root, WandKind kind) { //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) if (!Ready || SpellDataField == null || SecretField == null) { Plugin.Log.LogError((object)("Cannot configure " + kind.ToString() + ": spell lifecycle initialization failed. See the startup error above.")); return false; } List children = GetChildren(root); if (children.Count < 4) { Plugin.Log.LogError((object)("Cannot configure " + kind.ToString() + ": donor needs four distinct child spells.")); return false; } ManagedWandState component = root.GetComponent(); if ((Object)(object)component != (Object)null) { return true; } component = root.AddComponent(); SpellDefinition[] array = SpellCatalog.For(kind); try { for (int i = 0; i < children.Count; i++) { Spell val = children[i]; SpellDefinition spellDefinition = ((i < array.Length) ? array[i] : null); Object val2 = (Object)(object)Object.Instantiate(val.SpellData); component.Data.Add(val2); val2.name = ((spellDefinition != null) ? spellDefinition.Key : ("YAPYAPEXP_DISABLED_" + i)); SetRequired(val2, "voiceCommandKey", (spellDefinition != null) ? spellDefinition.Key : string.Empty); SetRequired(val2, "spellName", (spellDefinition != null) ? spellDefinition.LocalName : ""); SetRequired(val2, "charges", spellDefinition?.Charges ?? 0); SetRequired(val2, "cooldown", spellDefinition?.Cooldown ?? 999f); SetRequired(val2, "chargePerCast", 1); SetRequired(val2, "chargeCostPerSecondCast", 0); SetRequired(val2, "chargesRegenPerInterval", (spellDefinition != null) ? 1 : 0); SetRequired(val2, "chargeRegenInterval", spellDefinition?.Regen ?? 1f); SetRequired(val2, "chargeRegenDelay", 0f); SetRequired(val2, "chargeColor", (object)((kind == WandKind.Frost) ? new Color(0.35f, 0.85f, 1f) : new Color(0.85f, 0.35f, 1f))); string[] array2 = new string[4] { "castVFXPrefab", "spawnVFXPrefab", "endVFXPrefab", "impactVFXPrefab" }; foreach (string name in array2) { SetRequired(val2, name, null); } FieldInfo field = typeof(Spell).GetField("castVFX", Fields); if (field != null) { field.SetValue(val, null); } SpellDataField.SetValue(val, val2); SecretField.SetValue(val, spellDefinition == null); val.OverrideSecret = spellDefinition == null; ((Behaviour)val).enabled = true; } Plugin.Log.LogInfo((object)(kind.ToString() + ": four spells ready; Mirror component layout unchanged.")); return true; } catch (Exception ex) { Plugin.Log.LogError((object)("Wand spell setup failed; refusing to spawn partial wand: " + ex)); return false; } } private static void SetRequired(object target, string name, object value) { FieldInfo? field = target.GetType().GetField(name, Fields); if (field == null) { throw new MissingFieldException(target.GetType().FullName, name); } field.SetValue(target, value); } internal static bool TryGetKind(Spell spell, out WandKind kind) { kind = WandKind.Chaos; if ((Object)(object)spell == (Object)null) { return false; } NetworkIdentity componentInParent = ((Component)spell).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { return false; } if (componentInParent.assetId == 1497712210) { kind = WandKind.Frost; return true; } return componentInParent.assetId == 1497711432; } internal static bool IsManagedChild(Spell spell) { if ((Object)(object)spell != (Object)null && !(spell is VoiceSpell) && TryGetKind(spell, out var _) && (Object)(object)spell.SpellData != (Object)null) { return ((Object)spell.SpellData).name.StartsWith("YAPYAPEXP_", StringComparison.Ordinal); } return false; } internal static SpellDefinition Definition(Spell spell) { if (!IsManagedChild(spell)) { return null; } SpellDefinition spellDefinition = SpellCatalog.Find(spell.VoiceCommandKey); if (spellDefinition == null || !TryGetKind(spell, out var kind) || kind != spellDefinition.Kind) { return null; } return spellDefinition; } internal static bool IsHeld(Spell spell) { if ((Object)(object)spell == (Object)null || (Object)(object)spell.CasterIdentity == (Object)null) { return false; } NetworkIdentity componentInParent = ((Component)spell).GetComponentInParent(); NetworkPuppetWandProp val = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).GetComponentInChildren(true) : null); if ((Object)(object)val != (Object)null && (Object)(object)val.Spell != (Object)null && val.Spell.NetworkisWandActive) { return (Object)(object)val.Spell.CasterIdentity == (Object)(object)spell.CasterIdentity; } return false; } internal static void Activate(Spell spell) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: 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_0318: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) SpellDefinition spellDefinition = Definition(spell); if (!NetworkServer.active || spellDefinition == null || !IsHeld(spell) || !SpellVanilla.CanCast(spell)) { return; } GameObject val = null; Vector3 val2 = ((Component)spell.CasterIdentity).transform.position + Vector3.up * 0.5f; SpellTargets.Aim(spell, out var _, out var direction); if (spellDefinition.Range > 0f && spellDefinition.Id != SpellId.ChaosRoll) { if (!SpellTargets.FirstHit(spell, spellDefinition.Range, out var first)) { return; } val2 = ((RaycastHit)(ref first)).point + ((RaycastHit)(ref first)).normal * 0.08f; val = SpellTargets.Resolve(((RaycastHit)(ref first)).collider); if ((spellDefinition.Id == SpellId.FrostBind || spellDefinition.Id == SpellId.FrostShard || spellDefinition.Id == SpellId.ChaosBolt) && ((Object)(object)val == (Object)null || (spellDefinition.Id == SpellId.FrostShard && (Object)(object)val.GetComponent() == (Object)null))) { return; } } int num = 0; try { SpellVanilla.Activate(spell); switch (spellDefinition.Id) { case SpellId.FrostBind: FreezeState.ApplyTo(val, spellDefinition.Duration, frost: true); break; case SpellId.FrostShard: { FreezeState component = val.GetComponent(); int num2 = spellDefinition.Damage; if ((Object)(object)component != (Object)null && component.IsFrozen) { num2 += spellDefinition.FrozenBonus; component.Thaw(); } SpellTargets.Damage(val, spell.CasterIdentity, num2, direction); break; } case SpellId.FrostNova: foreach (GameObject item in SpellTargets.Nearby(spell, val2, spellDefinition.Radius)) { NetworkIdentity casterIdentity = spell.CasterIdentity; int damage = spellDefinition.Damage; Vector3 val3 = item.transform.position - val2; SpellTargets.Damage(item, casterIdentity, damage, ((Vector3)(ref val3)).normalized); if ((Object)(object)item != (Object)null) { FreezeState.ApplyTo(item, spellDefinition.Duration, frost: true); } } break; case SpellId.FrostBlizzard: case SpellId.ChaosVortex: SpellZone.Create(spell, spellDefinition, val2); break; case SpellId.ChaosRoll: num = SpellCatalog.Roll(DiceRandom); ApplyRoll(spell, num, val2); Plugin.Log.LogInfo((object)("CHAOS ROLL face=" + num + " | " + SpellCatalog.RollName(num, russian: false))); break; case SpellId.ChaosBolt: SpellTargets.Damage(val, spell.CasterIdentity, spellDefinition.Damage + Random.Range(0, spellDefinition.DamageVariance + 1), direction); if ((Object)(object)val != (Object)null) { if ((Object)(object)val.GetComponent() != (Object)null) { FreezeState.ApplyTo(val, spellDefinition.Duration, frost: false); break; } SpellTargets.DamageProp(val, spell.CasterIdentity, 8, direction); SpellTargets.Impulse(val, direction * 5f + Vector3.up * 5f); } break; case SpellId.ChaosBurst: Burst(spell, val2, spellDefinition.Radius, 8f, spellDefinition.Damage, spellDefinition.Duration); break; } spell.RpcPlayEffect((SpellEffectType)((spellDefinition.Id == SpellId.FrostBlizzard || spellDefinition.Id == SpellId.ChaosVortex) ? 1 : 3), val2, (num > 0) ? ChaosRollSync.Encode(num) : Quaternion.LookRotation(direction)); Plugin.Log.LogInfo((object)("CAST " + spellDefinition.Id.ToString() + " | charges=" + spell.CurrentCharges + "/" + spell.MaxCharges)); } catch (Exception ex) { Plugin.Log.LogError((object)("Spell " + spellDefinition.Id.ToString() + " failed: " + ex)); } finally { if ((Object)(object)spell != (Object)null && spell.IsCasting) { SpellVanilla.Deactivate(spell); } } } private static void ApplyRoll(Spell spell, int roll, Vector3 center) { //IL_0022: 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_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) switch (roll) { case 1: Burst(spell, center, 4.5f, 4f, 0, 0f); break; case 2: { foreach (GameObject item in SpellTargets.Nearby(spell, center, 5.5f)) { Vector3 val2 = center - item.transform.position; SpellTargets.Impulse(item, ((Vector3)(ref val2)).normalized * 5.5f + Vector3.up); } break; } case 3: case 4: { RaycastHit first; GameObject val = (SpellTargets.FirstHit(spell, 12f, out first) ? SpellTargets.Resolve(((RaycastHit)(ref first)).collider) : null); if ((Object)(object)val != (Object)null) { if (roll == 4) { FreezeState.ApplyTo(val, 2.5f, frost: true); } else if ((Object)(object)val.GetComponent() != (Object)null) { FreezeState.ApplyTo(val, 1f, frost: false); } else { SpellTargets.Impulse(val, Vector3.up * 6.5f); } break; } { foreach (GameObject item2 in SpellTargets.Nearby(spell, center, 3f)) { if (roll == 4) { FreezeState.ApplyTo(item2, 1f, frost: true); } else if ((Object)(object)item2.GetComponent() != (Object)null) { FreezeState.ApplyTo(item2, 0.75f, frost: false); } else { SpellTargets.Impulse(item2, Vector3.up * 5f); } } break; } } case 5: { foreach (GameObject item3 in SpellTargets.Nearby(spell, center, 5.5f)) { float num = Random.Range(0f, MathF.PI * 2f); SpellTargets.Impulse(item3, new Vector3(Mathf.Cos(num) * 6.5f, 2f, Mathf.Sin(num) * 6.5f)); } break; } case 6: Burst(spell, center, 6f, 8f, 0, 0f); spell.SetCurrentCharges(Math.Min(spell.MaxCharges, spell.CurrentCharges + 1)); break; } } private static void Burst(Spell spell, Vector3 center, float radius, float force, int damage, float stun) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) foreach (GameObject item in SpellTargets.Nearby(spell, center, radius)) { Vector3 val = item.transform.position - center; Vector3 normalized = ((Vector3)(ref val)).normalized; SpellTargets.Damage(item, spell.CasterIdentity, damage, normalized); if (!((Object)(object)item == (Object)null)) { if (stun > 0f && (Object)(object)item.GetComponent() != (Object)null) { FreezeState.ApplyTo(item, stun, frost: false); } else { SpellTargets.Impulse(item, normalized * force + Vector3.up * 1.5f); } } } } } internal sealed class ManagedWandState : MonoBehaviour { internal readonly List Data = new List(); private void OnDestroy() { foreach (Object datum in Data) { if (datum != (Object)null) { Object.Destroy(datum); } } Data.Clear(); } } internal static class ExtraRules { internal const float VacuumCastRange = 8f; internal const int VacuumPropDamage = 6; internal const double VacuumDamageInterval = 0.5; internal static bool WithinVacuumReach(Vector3 caster, Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) Vector3 val = point - caster; return ((Vector3)(ref val)).sqrMagnitude <= 64f; } internal static bool VacuumTargetInRange(Vector3 caster, Vector3 center, Vector3 point, float radius) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (radius > 0f && WithinVacuumReach(caster, center) && WithinVacuumReach(caster, point)) { Vector3 val = point - center; return ((Vector3)(ref val)).sqrMagnitude <= radius * radius; } return false; } internal static float Suction(float distance, float radius) { if (radius <= 0f || distance >= radius) { return 0f; } float num = 1f - Math.Max(0f, distance) / radius; return 14f + 46f * num * num; } internal static int RainCount(double age, double interval, int max) { if (!(age < 0.0) && !(interval <= 0.0)) { return Math.Min(max, 1 + (int)Math.Floor(age / interval)); } return 0; } internal static Vector3 OrbitPoint(Vector3 center, float radius, double age, int index, int count) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) double num = age * 1.6 + (double)index * Math.PI * 2.0 / (double)Math.Max(1, count); return center + new Vector3((float)Math.Cos(num) * radius, 1.15f, (float)Math.Sin(num) * radius); } internal static Vector3 OrbitForce(Vector3 error, Vector3 velocity, Vector3 targetVelocity, Vector3 gravity) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) return Vector3.ClampMagnitude(error * 18f + (targetVelocity - velocity) * 7f - gravity, 32f); } internal static bool PortalCrossing(Vector3 previous, Vector3 current, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (previous.z <= 0f || current.z > 0.12f || current.z >= previous.z) { return false; } float val = previous.z / (previous.z - current.z); val = Math.Max(0f, Math.Min(1f, val)); float num = previous.x + (current.x - previous.x) * val; float num2 = previous.y + (current.y - previous.y) * val; return num * num + num2 * num2 < radius * radius; } internal static bool PortalContact(Vector3 local, float bodyRadius, float portalRadius) { //IL_0012: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) float num = portalRadius - bodyRadius * 0.25f; if (num > 0f && Math.Abs(local.z) <= bodyRadius + 0.18f) { return local.x * local.x + local.y * local.y < num * num; } return false; } internal static bool InPuddle(Vector3 point, Vector3 center, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) Vector3 val = point - center; if (val.y >= -0.12f && val.y <= 1.6f) { return val.x * val.x + val.z * val.z <= radius * radius; } return false; } } internal sealed class EffectPulse { private double next; internal EffectPulse(double start, double interval) { next = start + interval; } internal bool Tick(double now, double interval) { if (now < next) { return false; } next = now + interval; return true; } } internal sealed class ExtraLifetime { internal double Started; internal double Expires; internal bool Paired; internal bool Stopped; internal ExtraLifetime(double now, double duration) { Started = now; Expires = now + duration; } internal bool Alive(double now) { if (!Stopped) { return now < Expires; } return false; } internal bool Pair(double now, double duration) { if (Paired || !Alive(now)) { return false; } Paired = true; Expires = now + duration; return true; } internal void Stop() { Stopped = true; } } internal sealed class EffectClaims { private readonly Dictionary owners = new Dictionary(); internal int Count => owners.Count; internal bool Claim(T item, int owner) { if (owners.TryGetValue(item, out var value)) { return value == owner; } owners.Add(item, owner); return true; } internal bool Contains(T item) { return owners.ContainsKey(item); } internal void Release(T item, int owner) { if (owners.TryGetValue(item, out var value) && value == owner) { owners.Remove(item); } } } internal static class ExtraPhysics { internal static bool Eligible(Rigidbody body, bool allowWands = false) { //IL_001f: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)body == (Object)null || !((Component)body).gameObject.activeInHierarchy || body.isKinematic || (body.constraints & 0xE) != 0 || body.mass > 45f || (Object)(object)((Component)body).GetComponentInParent() != (Object)null || (Object)(object)((Component)body).GetComponentInParent() != (Object)null) { return false; } NetworkIdentity componentInParent = ((Component)body).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null || componentInParent.netId == 0 || componentInParent.connectionToClient != null || !NetworkServer.spawned.ContainsKey(componentInParent.netId)) { return false; } NetworkPuppetProp componentInParent2 = ((Component)body).GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null && (componentInParent2.IsShopItem || (int)componentInParent2.CurrentState.state != 0 || (!allowWands && componentInParent2 is NetworkPuppetWandProp))) { return false; } return (Object)(object)((Component)body).GetComponent() == (Object)null; } internal static List Bodies(ExtraSpell spell, Vector3 point, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (GameObject item in SpellTargets.Nearby((Spell)(object)spell, point, radius)) { Rigidbody[] componentsInChildren = item.GetComponentsInChildren(); foreach (Rigidbody val in componentsInChildren) { if (Eligible(val) && !list.Contains(val)) { list.Add(val); } } } list.Sort(delegate(Rigidbody a, Rigidbody b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = a.worldCenterOfMass - point; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; val2 = b.worldCenterOfMass - point; return sqrMagnitude.CompareTo(((Vector3)(ref val2)).sqrMagnitude); }); return list; } internal static bool Clear(Vector3 point, float radius, Rigidbody ignore = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(point, radius, -1, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i].attachedRigidbody != (Object)(object)ignore || (Object)(object)ignore == (Object)null) { return false; } } return true; } internal static Quaternion Frame(Vector3 normal) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) return Quaternion.LookRotation(normal, (Mathf.Abs(normal.y) > 0.9f) ? Vector3.forward : Vector3.up); } } internal sealed class ExtraZone : MonoBehaviour { private sealed class TimedObject { internal GameObject Object; internal double Expires; } private sealed class FireParticle { internal Vector3 Position; internal Vector3 Velocity; internal double Expires; } internal static readonly List Active = new List(); private static readonly EffectClaims Orbits = new EffectClaims(); private static readonly Dictionary PortalCooldown = new Dictionary(); private static int nextOwner; internal ExtraSpell Spell; internal ExtraLifetime Life; internal Vector3 A; internal Vector3 B; private Quaternion frameA; private Quaternion frameB; private double heartbeat; private EffectPulse damagePulse; private int emitted; private int claimOwner; private readonly List orbit = new List(); private readonly Dictionary previous = new Dictionary(); private NetworkIdentity[] fish; private GameObject fireHitbox; private readonly List spawned = new List(); private readonly List drops = new List(); private bool ended; internal ExtraDefinition Definition => Spell.Definition; internal static bool TryCast(ExtraSpell spell, Vector3 point, Vector3 normal) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) double time = NetworkTime.time; ExtraDefinition definition = spell.Definition; if (definition.Id == ExtraId.Vacuum) { SpellTargets.Aim((Spell)(object)spell, out var origin, out var _); if (!ExtraRules.WithinVacuumReach(origin, point + normal * 0.55f)) { return false; } } if (definition.Id == ExtraId.Rift && (Object)(object)spell.Zone != (Object)null && spell.Zone.Life.Alive(time) && !spell.Zone.Life.Paired) { ExtraZone zone = spell.Zone; Vector3 val = point - zone.A; if (((Vector3)(ref val)).sqrMagnitude < 9f) { return false; } zone.B = point + normal * 0.15f; zone.frameB = ExtraPhysics.Frame(normal); if (!zone.Life.Pair(time, definition.Duration)) { return false; } zone.SendVisuals(); Plugin.Log.LogInfo((object)("RIFT pair active for " + definition.Duration + " seconds")); return true; } NetworkIdentity[] prefabs = null; GameObject prefab = null; if (definition.Id == ExtraId.FishRain && !ExtraNativeAssets.TryFish(spell, out prefabs)) { return false; } if (definition.Id == ExtraId.IgnisRain && !ExtraNativeAssets.TryFire(spell, out prefab)) { return false; } List list = null; if (definition.Id == ExtraId.Orbit) { list = (from x in ExtraPhysics.Bodies(spell, point + Vector3.up, 4f) where !Orbits.Contains(x) select x).Take(4).ToList(); if ((Object)(object)spell.Zone != (Object)null) { spell.Zone.End(); list = (from x in ExtraPhysics.Bodies(spell, point + Vector3.up, 4f) where !Orbits.Contains(x) select x).Take(4).ToList(); } if (list.Count == 0) { return false; } } if ((Object)(object)spell.Zone != (Object)null) { spell.Zone.End(); } while (Active.Count >= 16) { Active[0].End(); } ExtraZone extraZone = new GameObject("YAPYAPExpanded_Extra_" + definition.Id).AddComponent(); extraZone.Spell = spell; spell.Zone = extraZone; extraZone.A = point + ((definition.Id == ExtraId.Rift) ? (normal * 0.15f) : ((definition.Id == ExtraId.Vacuum) ? (normal * 0.55f) : (Vector3.up * 0.08f))); extraZone.frameA = ExtraPhysics.Frame(normal); extraZone.fish = prefabs; extraZone.fireHitbox = prefab; extraZone.Life = new ExtraLifetime(time, (definition.Id == ExtraId.Rift) ? 10f : definition.Duration); extraZone.damagePulse = new EffectPulse(time, 0.5); extraZone.claimOwner = ++nextOwner; if (list != null) { foreach (Rigidbody item in list) { if (Orbits.Claim(item, extraZone.claimOwner)) { extraZone.orbit.Add(item); } } } Active.Add(extraZone); extraZone.SendVisuals(); return true; } private void FixedUpdate() { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (ended) { return; } if (NetworkServer.active && !((Object)(object)Spell == (Object)null) && !((Object)(object)((Spell)Spell).CasterIdentity == (Object)null)) { Pawn component = ((Component)((Spell)Spell).CasterIdentity).GetComponent(); if (component == null || (!component.IsDead && !component.IsExtracted)) { try { double time = NetworkTime.time; bool flag = Life.Alive(time); if (flag) { if (Definition.Id == ExtraId.Orbit) { A = ((Component)((Spell)Spell).CasterIdentity).transform.position; } if (time >= heartbeat) { SendVisuals(); heartbeat = time + 0.5; } switch (Definition.Id) { case ExtraId.Vacuum: Vacuum(time); break; case ExtraId.Rift: if (Life.Paired) { Portals(time); } break; case ExtraId.Orbit: Orbit(time); break; case ExtraId.IgnisRain: Rain(time, isFish: false); break; case ExtraId.FishRain: Rain(time, isFish: true); break; } } TickDrops(time); for (int num = spawned.Count - 1; num >= 0; num--) { TimedObject timedObject = spawned[num]; if ((Object)(object)timedObject.Object == (Object)null || time >= timedObject.Expires) { if ((Object)(object)timedObject.Object != (Object)null) { NetworkServer.Destroy(timedObject.Object); } spawned.RemoveAt(num); } } if (!flag && drops.Count == 0 && spawned.Count == 0) { End(); } return; } catch (Exception ex) { Plugin.Log.LogError((object)("Extra effect ended safely: " + ex)); End(); return; } } } End(); } private void Vacuum(double now) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) SpellTargets.Aim((Spell)(object)Spell, out var origin, out var _); if (!ExtraRules.WithinVacuumReach(origin, A)) { End(); return; } bool flag = damagePulse.Tick(now, 0.5); HashSet hashSet = (flag ? new HashSet() : null); foreach (Rigidbody item in ExtraPhysics.Bodies(Spell, A, Definition.Radius)) { if (!ExtraPhysics.Eligible(item) || Orbits.Contains(item) || !ExtraRules.VacuumTargetInRange(origin, A, item.worldCenterOfMass, Definition.Radius)) { continue; } Vector3 val = A - item.worldCenterOfMass; float num = ExtraRules.Suction(((Vector3)(ref val)).magnitude, Definition.Radius); item.AddForce(((Vector3)(ref val)).normalized * num - item.linearVelocity * 2.2f - (item.useGravity ? (Physics.gravity * 0.85f) : Vector3.zero), (ForceMode)5); item.linearVelocity = Vector3.ClampMagnitude(item.linearVelocity, 14f); if (flag) { NetworkIdentity componentInParent = ((Component)item).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && hashSet.Add(componentInParent)) { SpellTargets.DamageProp(((Component)componentInParent).gameObject, ((Spell)Spell).CasterIdentity, 6, ((Vector3)(ref val)).normalized); } } } } private void Orbit(double now) { //IL_002a: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) for (int num = orbit.Count - 1; num >= 0; num--) { Rigidbody val = orbit[num]; if (ExtraPhysics.Eligible(val)) { Vector3 val2 = val.position - A; if (!(((Vector3)(ref val2)).sqrMagnitude > 64f)) { double num2 = now - Life.Started; Vector3 val3 = ExtraRules.OrbitPoint(A, Definition.Radius, num2, num, orbit.Count); Vector3 val4 = ExtraRules.OrbitPoint(A, Definition.Radius, num2 + 0.02, num, orbit.Count); Vector3 val5 = Vector3.zero; Rigidbody component = ((Component)((Spell)Spell).CasterIdentity).GetComponent(); if ((Object)(object)component != (Object)null) { val5 = component.linearVelocity; } val.AddForce(ExtraRules.OrbitForce(val3 - val.worldCenterOfMass, val.linearVelocity, (val4 - val3) / 0.02f + val5, val.useGravity ? Physics.gravity : Vector3.zero), (ForceMode)5); continue; } } Orbits.Release(val, claimOwner); orbit.RemoveAt(num); } } private void Portals(double now) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) Rigidbody[] array = (from x in PortalCooldown where (Object)(object)x.Key == (Object)null || x.Value <= now select x.Key).ToArray(); foreach (Rigidbody key in array) { PortalCooldown.Remove(key); } HashSet hashSet = new HashSet(); PortalEnd(A, frameA, B, frameB, now, hashSet); PortalEnd(B, frameB, A, frameA, now, hashSet); foreach (Rigidbody item in hashSet) { if ((Object)(object)item != (Object)null) { previous[item] = item.worldCenterOfMass; } } array = previous.Keys.ToArray(); foreach (Rigidbody val in array) { if ((Object)(object)val == (Object)null || !hashSet.Contains(val)) { previous.Remove(val); } } } private void PortalEnd(Vector3 from, Quaternion fromFrame, Vector3 to, Quaternion toFrame, double now, HashSet seen) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0235: 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_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); Collider[] array = Physics.OverlapSphere(from, 2.4f, -1, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { Rigidbody attachedRigidbody = array[i].attachedRigidbody; if (!ExtraPhysics.Eligible(attachedRigidbody, allowWands: true) || !hashSet.Add(attachedRigidbody)) { continue; } seen.Add(attachedRigidbody); if (Orbits.Contains(attachedRigidbody) || PortalCooldown.ContainsKey(attachedRigidbody)) { continue; } Vector3 worldCenterOfMass = attachedRigidbody.worldCenterOfMass; if (!previous.TryGetValue(attachedRigidbody, out var value)) { value = worldCenterOfMass - attachedRigidbody.linearVelocity * Time.fixedDeltaTime; } Quaternion val = Quaternion.Inverse(fromFrame); float num = 0.12f; Collider[] componentsInChildren = ((Component)attachedRigidbody).GetComponentsInChildren(); foreach (Collider val2 in componentsInChildren) { if ((Object)(object)val2.attachedRigidbody == (Object)(object)attachedRigidbody && !val2.isTrigger) { float num2 = num; Bounds bounds = val2.bounds; float x = ((Bounds)(ref bounds)).extents.x; bounds = val2.bounds; float y = ((Bounds)(ref bounds)).extents.y; bounds = val2.bounds; num = Mathf.Max(num2, Mathf.Max(x, Mathf.Max(y, ((Bounds)(ref bounds)).extents.z))); } } if (num > 0.8f) { continue; } Vector3 val3 = val * (value - from); Vector3 current = val * (worldCenterOfMass - from); val3.z -= num; current.z -= num; if (!ExtraRules.PortalCrossing(val3, current, Definition.Radius - num * 0.25f) && !ExtraRules.PortalContact(val * (worldCenterOfMass - from), num, Definition.Radius)) { continue; } Quaternion val4 = toFrame * Quaternion.Euler(0f, 180f, 0f) * val; Vector3 val5 = val * (worldCenterOfMass - from); val5.z = 0f; Vector3 val6 = to + toFrame * new Vector3(0f - val5.x, val5.y, num + 0.22f); bool flag = false; for (int k = 0; k < 4; k++) { val6 = to + toFrame * new Vector3(0f - val5.x, val5.y, num + 0.25f + (float)k * 0.35f); if (Physics.Linecast(to + toFrame * Vector3.forward * 0.06f, val6, -1, (QueryTriggerInteraction)1)) { break; } if (ExtraPhysics.Clear(val6, num * 0.95f, attachedRigidbody)) { flag = true; break; } } if (!flag) { continue; } Vector3 linearVelocity = val4 * attachedRigidbody.linearVelocity; Vector3 angularVelocity = val4 * attachedRigidbody.angularVelocity; attachedRigidbody.position = val6 + val4 * (attachedRigidbody.position - worldCenterOfMass); attachedRigidbody.rotation = val4 * attachedRigidbody.rotation; NetworkTransformBase[] componentsInParent = ((Component)attachedRigidbody).GetComponentsInParent(); foreach (NetworkTransformBase val7 in componentsInParent) { if ((Object)(object)val7.target == (Object)(object)((Component)attachedRigidbody).transform) { val7.ServerTeleport(attachedRigidbody.position, attachedRigidbody.rotation); } } attachedRigidbody.linearVelocity = linearVelocity; attachedRigidbody.angularVelocity = angularVelocity; attachedRigidbody.WakeUp(); PortalCooldown[attachedRigidbody] = now + 0.65; previous[attachedRigidbody] = val6; Plugin.Log.LogInfo((object)("RIFT transported " + ((Object)attachedRigidbody).name)); } } private void Rain(double now, bool isFish) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) int num = ExtraRules.RainCount(now - Life.Started, isFish ? 0.4 : 0.5, isFish ? 10 : 8); if (emitted >= num) { return; } emitted = num; Vector2 val = Random.insideUnitCircle * Definition.Radius; Vector3 val2 = A + new Vector3(val.x, 0f, val.y); Vector3 val3 = val2 + Vector3.up * 4f; RaycastHit val4 = default(RaycastHit); if (Physics.Raycast(val2 + Vector3.up * 0.2f, Vector3.up, ref val4, 4f, -1, (QueryTriggerInteraction)1)) { val3 = ((RaycastHit)(ref val4)).point - Vector3.up * 0.4f; } if (val3.y - val2.y < 0.65f || !ExtraPhysics.Clear(val3, 0.15f)) { return; } if (isFish) { GameObject val5 = GameManager.SpawnNetworkPrefab(fish[Random.Range(0, fish.Length)], val3, Random.rotation, Vector3.one * 0.4f, false); if ((Object)(object)val5 == (Object)null) { return; } spawned.Add(new TimedObject { Object = val5, Expires = now + 12.0 }); Rigidbody[] componentsInChildren = val5.GetComponentsInChildren(); foreach (Rigidbody val6 in componentsInChildren) { if (!val6.isKinematic) { val6.linearVelocity = Vector3.down * 1.5f; } } } else { Vector3 val7 = Vector3.down * 8f; drops.Add(new FireParticle { Position = val3, Velocity = val7, Expires = now + 1.5 }); ((Spell)Spell).RpcPlayEffect((SpellEffectType)3, val3, Quaternion.LookRotation(val7)); } } private void TickDrops(double now) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) RaycastHit hit = default(RaycastHit); for (int num = drops.Count - 1; num >= 0; num--) { FireParticle fireParticle = drops[num]; if (now >= fireParticle.Expires) { drops.RemoveAt(num); } else { Vector3 val = fireParticle.Velocity * Time.fixedDeltaTime; if (Physics.SphereCast(fireParticle.Position, 0.1f, ((Vector3)(ref val)).normalized, ref hit, ((Vector3)(ref val)).magnitude, -1, (QueryTriggerInteraction)1)) { ExtraNativeAssets.FireImpact(Spell, fireHitbox, hit); drops.RemoveAt(num); } else { fireParticle.Position += val; } } } } private void SendVisuals() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Spell == (Object)null) && NetworkServer.active && Life != null && Life.Alive(NetworkTime.time)) { ((Spell)Spell).RpcPlayEffect((SpellEffectType)1, A, frameA); if (Life.Paired) { ((Spell)Spell).RpcPlayEffect((SpellEffectType)3, B, frameB); } } } internal void End() { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) if (ended) { return; } ended = true; Life?.Stop(); Active.Remove(this); foreach (Rigidbody item in orbit) { Orbits.Release(item, claimOwner); } orbit.Clear(); previous.Clear(); drops.Clear(); foreach (TimedObject item2 in spawned) { if ((Object)(object)item2.Object != (Object)null) { if (NetworkServer.active) { NetworkServer.Destroy(item2.Object); } else { Object.Destroy((Object)(object)item2.Object); } } } spawned.Clear(); if ((Object)(object)Spell != (Object)null) { if ((Object)(object)Spell.Zone == (Object)(object)this) { Spell.Zone = null; } if (NetworkServer.active && ((NetworkBehaviour)Spell).netId != 0) { ((Spell)Spell).RpcPlayEffect((SpellEffectType)4, Vector3.zero, Quaternion.identity); } Spell.ClearVisuals(); } if (Active.Count == 0) { PortalCooldown.Clear(); } ((Behaviour)this).enabled = false; Object.Destroy((Object)(object)((Component)this).gameObject); } private void OnDestroy() { End(); } } internal static class ExtraNativeAssets { private static readonly BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; internal static bool TryFish(ExtraSpell spell, out NetworkIdentity[] prefabs) { FishifySpell componentInChildren = ((Component)((NetworkBehaviour)spell).netIdentity).GetComponentInChildren(true); FieldInfo field = typeof(FishifySpell).GetField("fishPrefabs", Fields); prefabs = (((Object)(object)componentInChildren != (Object)null && field != null) ? (field.GetValue(componentInChildren) as NetworkIdentity[]) : null)?.Where((NetworkIdentity x) => (Object)(object)x != (Object)null && (Object)(object)((Component)x).GetComponentInChildren(true) != (Object)null).ToArray(); if (prefabs != null && prefabs.Length != 0) { return true; } Plugin.Log.LogWarning((object)"FISH RAIN: vanilla fish prefabs unavailable; no charge consumed."); return false; } internal static bool TryFire(ExtraSpell spell, out GameObject prefab) { FireSelfSpell componentInChildren = ((Component)((NetworkBehaviour)spell).netIdentity).GetComponentInChildren(true); FieldInfo field = typeof(FireSelfSpell).GetField("hitboxPrefab", Fields); prefab = (GameObject)(((Object)(object)componentInChildren != (Object)null && field != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent() != (Object)null && (Object)(object)prefab.GetComponent() != (Object)null) { return true; } Plugin.Log.LogWarning((object)"IGNIS RAIN: vanilla fire hitbox unavailable; no charge consumed."); return false; } internal static void FireImpact(ExtraSpell spell, GameObject prefab, RaycastHit hit) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null || (Object)(object)((Spell)spell).CasterIdentity == (Object)null) { return; } GameObject val = Object.Instantiate(prefab, ((RaycastHit)(ref hit)).point + ((RaycastHit)(ref hit)).normal * 0.12f, Quaternion.identity); HitboxBase component = val.GetComponent(); component.doTtl = true; component.ttl = 0.12f; component.Networkdamage = 6; component.propDamage = 4; component.NetworkpushForce = 1f; component.owner = ((Spell)spell).CasterIdentity; component.allowSelfHit = false; component.forceRagdoll = false; component.forceNpcStun = false; component.NetworkdoLineOfSight = true; float num = 0f; Collider[] componentsInChildren = val.GetComponentsInChildren(); foreach (Collider val2 in componentsInChildren) { float num2 = num; Bounds bounds = val2.bounds; Vector3 extents = ((Bounds)(ref bounds)).extents; num = Mathf.Max(num2, ((Vector3)(ref extents)).magnitude); } if (num > 0.001f) { Transform transform = val.transform; transform.localScale *= 0.65f / num; } NetworkServer.Spawn(val, (NetworkConnectionToClient)null); Type type = typeof(Spell).Assembly.GetType("YAPYAP.IIgnitable"); if (type != null) { Component componentInParent = ((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent(type); if ((Object)(object)componentInParent != (Object)null) { type.GetMethod("SetIgnited").Invoke(componentInParent, new object[1] { true }); } } } } internal sealed class ExtraVisual : MonoBehaviour { internal static readonly List Active = new List(); internal ExtraSpell Spell; internal double Expires; private LineRenderer line; private Material material; private Mesh disk; internal static Color Tint(ExtraId id) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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) return (Color)(id switch { ExtraId.IgnisRain => new Color(1f, 0.3f, 0.05f), ExtraId.Rift => new Color(0.65f, 0.4f, 1f), ExtraId.SlipperyYuk => new Color(0.45f, 0.85f, 0.08f), ExtraId.FishRain => new Color(0.2f, 0.9f, 0.65f), ExtraId.Orbit => new Color(0.35f, 0.55f, 1f), _ => new Color(0.65f, 0.95f, 1f), }); } internal static Material NewMaterial(Color color) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Color"); if ((Object)(object)val == (Object)null) { return null; } return new Material(val) { color = color }; } internal static void Refresh(ref ExtraVisual visual, ExtraSpell spell, Vector3 position, Quaternion rotation) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_002a: Expected O, but got Unknown if ((Object)(object)visual == (Object)null) { GameObject val = new GameObject("YAPYAPExpanded_" + spell.Definition.Name + "_Visual"); visual = val.AddComponent(); visual.Spell = spell; visual.Initialize(); Active.Add(visual); } ((Component)visual).transform.SetPositionAndRotation(position, rotation); visual.Expires = NetworkTime.time + 1.25; } private void Initialize() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Expected O, but got Unknown //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) material = NewMaterial(Tint(Spell.Definition.Id)); if ((Object)(object)material == (Object)null) { return; } line = ((Component)this).gameObject.AddComponent(); ((Renderer)line).sharedMaterial = material; line.useWorldSpace = true; line.widthMultiplier = 0.055f; line.positionCount = 97; if (Spell.Definition.Id == ExtraId.Vacuum) { GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)obj).name = "VacuumOrb"; obj.transform.SetParent(((Component)this).transform, false); obj.transform.localScale = Vector3.one * 1.1f; Collider component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { component.enabled = false; Object.Destroy((Object)(object)component); } obj.GetComponent().sharedMaterial = material; Color color = Tint(ExtraId.Vacuum); color.a = 0.28f; material.color = color; } if (Spell.Definition.Id == ExtraId.SlipperyYuk) { Vector3[] array = (Vector3[])(object)new Vector3[50]; int[] array2 = new int[144]; for (int i = 0; i <= 48; i++) { float num = (float)i * MathF.PI * 2f / 48f; array[i + 1] = new Vector3(Mathf.Cos(num), Mathf.Sin(num), 0f) * Spell.Definition.Radius; } for (int j = 0; j < 48; j++) { array2[j * 3] = 0; array2[j * 3 + 1] = j + 2; array2[j * 3 + 2] = j + 1; } disk = new Mesh(); disk.vertices = array; disk.triangles = array2; disk.RecalculateNormals(); ((Component)this).gameObject.AddComponent().sharedMesh = disk; ((Renderer)((Component)this).gameObject.AddComponent()).sharedMaterial = material; Color color2 = Tint(Spell.Definition.Id); color2.a = 0.55f; material.color = color2; } } private void Update() { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Spell == (Object)null || !NetworkClient.active || NetworkTime.time >= Expires) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { if ((Object)(object)line == (Object)null) { return; } ExtraDefinition definition = Spell.Definition; if (definition.Id == ExtraId.Orbit && (Object)(object)((Spell)Spell).CasterIdentity != (Object)null) { ((Component)this).transform.position = ((Component)((Spell)Spell).CasterIdentity).transform.position; } Vector3 val = default(Vector3); for (int i = 0; i < 97; i++) { float num = (float)i / 96f * MathF.PI * 2f; if (definition.Id == ExtraId.Rift) { val = ((Component)this).transform.rotation * new Vector3(Mathf.Cos(num), Mathf.Sin(num), 0f) * definition.Radius; } else if (definition.Id == ExtraId.Vacuum) { int num2 = Mathf.Min(2, i / 32); num = (float)(i % 32) * MathF.PI * 2f / 31f; float num3 = 0.57f; val = (Vector3)(num2 switch { 1 => new Vector3(0f, Mathf.Cos(num) * num3, Mathf.Sin(num) * num3), 0 => new Vector3(Mathf.Cos(num) * num3, Mathf.Sin(num) * num3, 0f), _ => new Vector3(Mathf.Cos(num) * num3, 0f, Mathf.Sin(num) * num3), }); } else { ((Vector3)(ref val))..ctor(Mathf.Cos(num) * definition.Radius, (definition.Id == ExtraId.Orbit) ? 1.15f : 0.035f, Mathf.Sin(num) * definition.Radius); } line.SetPosition(i, ((Component)this).transform.position + val); } } } internal static void FireDrop(Vector3 position, Vector3 direction) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("YAPYAPExpanded_FallingFire"); val.transform.position = position; val.AddComponent().Initialize(direction * 8f); } private void OnDestroy() { Active.Remove(this); if ((Object)(object)material != (Object)null) { Object.Destroy((Object)(object)material); } if ((Object)(object)disk != (Object)null) { Object.Destroy((Object)(object)disk); } } } internal sealed class FireDropVisual : MonoBehaviour { private Vector3 velocity; private float expires; private LineRenderer line; private Material material; internal void Initialize(Vector3 speed) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) velocity = speed; expires = Time.time + 1.5f; material = ExtraVisual.NewMaterial(new Color(1f, 0.3f, 0.02f)); line = ((Component)this).gameObject.AddComponent(); ((Renderer)line).sharedMaterial = material; line.positionCount = 2; line.startWidth = 0.17f; line.endWidth = 0.025f; line.useWorldSpace = true; } private void Update() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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) if (Time.time >= expires || !NetworkClient.active) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Vector3 val = velocity * Time.deltaTime; RaycastHit val2 = default(RaycastHit); if (Physics.SphereCast(((Component)this).transform.position, 0.1f, ((Vector3)(ref val)).normalized, ref val2, ((Vector3)(ref val)).magnitude, -1, (QueryTriggerInteraction)1)) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Transform transform = ((Component)this).transform; transform.position += val; line.SetPosition(0, ((Component)this).transform.position); line.SetPosition(1, ((Component)this).transform.position - velocity * 0.065f); } private void OnDestroy() { if ((Object)(object)material != (Object)null) { Object.Destroy((Object)(object)material); } } } internal static class ExtraVoicePhrases { internal static Dictionary Build(Dictionary original, IEnumerable grammar, Dictionary existing, bool russian) { List list = (from x in original.Values.Concat(existing.Values) where x != null select x).ToList(); HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (string[] value in original.Values) { if (value != null) { string[] array = value; foreach (string token in array) { Add(hashSet, token); } } } if (grammar != null) { foreach (string item in grammar) { Add(hashSet, item); } } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); ExtraDefinition[] all = ExtraCatalog.All; foreach (ExtraDefinition extraDefinition in all) { string root = (russian ? extraDefinition.RootRu : extraDefinition.RootEn); string ending = (russian ? extraDefinition.EndingRu : extraDefinition.EndingEn); IOrderedEnumerable orderedEnumerable = hashSet.OrderBy((string x) => (!string.Equals(x, root, StringComparison.OrdinalIgnoreCase)) ? 1 : 0).ThenBy((string x) => x, StringComparer.Ordinal); string[] array2 = hashSet.OrderBy((string x) => (!string.Equals(x, ending, StringComparison.OrdinalIgnoreCase)) ? 1 : 0).ThenBy((string x) => x, StringComparer.Ordinal).ToArray(); string[] array3 = null; foreach (string item2 in orderedEnumerable) { string[] array = array2; foreach (string text in array) { if (!string.Equals(item2, text, StringComparison.OrdinalIgnoreCase)) { string[] candidate = new string[2] { item2, text }; if (!list.Any((string[] x) => VoicePhraseBuilder.Conflicts(candidate, x))) { array3 = candidate; break; } } } if (array3 != null) { break; } } if (array3 != null) { dictionary.Add(extraDefinition.Key, array3); list.Add(array3); } } return dictionary; } private static void Add(HashSet pool, string token) { if (!string.IsNullOrWhiteSpace(token) && token.All(char.IsLetter)) { pool.Add(token.ToUpperInvariant()); } } } internal sealed class FreezeState : MonoBehaviour { private readonly List _restore = new List(); private double _frozenUntil; private double _stunnedUntil; private bool _captured; private NpcBehaviour _npc; internal bool IsFrozen { get { if (_captured) { return NetworkTime.time < _frozenUntil; } return false; } } internal static void ApplyTo(GameObject root, float seconds, bool frost) { if (!NetworkServer.active || (Object)(object)root == (Object)null || !root.activeInHierarchy || seconds <= 0f || (Object)(object)root.GetComponentInParent() != (Object)null) { return; } NpcBehaviour component = root.GetComponent(); if (!((Object)(object)component != (Object)null) || !component.IsKilled) { FreezeState freezeState = root.GetComponent(); if ((Object)(object)freezeState == (Object)null) { freezeState = root.AddComponent(); } freezeState.Apply(seconds, frost); } } internal void Apply(float seconds, bool frost) { if (NetworkServer.active && !(seconds <= 0f)) { if (!_captured) { Capture(); } if (frost) { _frozenUntil = Math.Max(_frozenUntil, NetworkTime.time + (double)seconds); } else { _stunnedUntil = Math.Max(_stunnedUntil, NetworkTime.time + (double)seconds); } ((Behaviour)this).enabled = true; } } internal void Thaw() { _frozenUntil = 0.0; if (NetworkTime.time >= _stunnedUntil) { Restore(); } } private void Capture() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) _captured = true; _npc = ((Component)this).GetComponent(); if ((Object)(object)_npc != (Object)null) { _npc.CollisionHitThisFrame = false; _npc.Networkspeed = 0f; } Rigidbody[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Rigidbody body in componentsInChildren) { if ((Object)(object)body == (Object)null) { continue; } RigidbodyConstraints originalConstraints = body.constraints; Vector3 velocity = body.linearVelocity; Vector3 angular = body.angularVelocity; _restore.Add(delegate { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)body == (Object)null)) { body.constraints = originalConstraints; if (!body.isKinematic && ((Object)(object)_npc == (Object)null || !_npc.IsKilled)) { body.linearVelocity = velocity; body.angularVelocity = angular; } } }); if (!body.isKinematic) { body.linearVelocity = Vector3.zero; body.angularVelocity = Vector3.zero; } body.constraints = (RigidbodyConstraints)126; } bool flag = (Object)(object)((Component)this).GetComponent() != (Object)null; Behaviour[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(true); Animator animator = default(Animator); foreach (Behaviour behaviour in componentsInChildren2) { if ((Object)(object)behaviour == (Object)null || (Object)(object)behaviour == (Object)(object)this) { continue; } ref Animator reference = ref animator; Behaviour obj = behaviour; reference = (Animator)(object)((obj is Animator) ? obj : null); if ((Object)(object)animator != (Object)null) { float speed = animator.speed; _restore.Add(delegate { if ((Object)(object)animator != (Object)null) { animator.speed = speed; } }); animator.speed = 0f; continue; } Type type = ((object)behaviour).GetType(); if (type.FullName == "UnityEngine.AI.NavMeshAgent") { PropertyInfo property = type.GetProperty("isStopped", BindingFlags.Instance | BindingFlags.Public); if (!(property != null) || !property.CanRead || !property.CanWrite) { continue; } try { object previous = property.GetValue(behaviour, null); property.SetValue(behaviour, true, null); _restore.Add(delegate { if ((Object)(object)behaviour != (Object)null) { property.SetValue(behaviour, previous, null); } }); } catch (Exception) { } continue; } string name = type.Name; string text = type.FullName ?? ""; bool flag2 = behaviour is NpcBehaviour || name.IndexOf("NpcAIAgent", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("AIInputProvider", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("StateMachine", StringComparison.OrdinalIgnoreCase) >= 0 || (text.StartsWith("YAPYAP.Npc", StringComparison.Ordinal) && (name.IndexOf("Movement", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Targeting", StringComparison.OrdinalIgnoreCase) >= 0)); if (!flag || !flag2) { continue; } bool wasEnabled = behaviour.enabled; _restore.Add(delegate { if ((Object)(object)behaviour != (Object)null && (behaviour is NpcBehaviour || (Object)(object)_npc == (Object)null || !_npc.IsKilled)) { behaviour.enabled = wasEnabled; } }); behaviour.enabled = false; } } private void Update() { if (!NetworkServer.active || ((Object)(object)_npc != (Object)null && _npc.IsKilled) || (NetworkTime.time >= _frozenUntil && NetworkTime.time >= _stunnedUntil)) { Restore(); } } private void OnDisable() { Restore(); } private void OnDestroy() { Restore(); } private void Restore() { if (!_captured) { return; } _captured = false; _frozenUntil = (_stunnedUntil = 0.0); foreach (Action item in _restore) { try { item(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Freeze restore: " + ex.Message)); } } _restore.Clear(); ((Behaviour)this).enabled = false; } } internal static class InventoryAppearance { private static Sprite _chaosIcon; private static Sprite _frostIcon; private static float _nextRefreshAt; private static readonly FieldInfo SlotIconField = typeof(UIInventorySlot).GetField("itemIcon", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static string ChaosDisplayName => Loc.Text("wand.chaos.name"); internal static string FrostDisplayName => Loc.Text("wand.frost.name"); internal static void Initialize() { _chaosIcon = LoadIcon("chaos.png", "YAPYAPExpanded_ChaosInventoryIcon"); _frostIcon = LoadIcon("frost.png", "YAPYAPExpanded_FrostInventoryIcon"); Plugin.Log.LogInfo((object)("Inventory icons loaded | Chaos=" + ((Object)(object)_chaosIcon != (Object)null) + " | Frost=" + ((Object)(object)_frostIcon != (Object)null))); } internal static void Update() { if (!(Time.unscaledTime < _nextRefreshAt)) { _nextRefreshAt = Time.unscaledTime + 0.5f; RefreshVisibleSlots(); } } internal static bool TryGetKind(NetworkPuppetProp prop, out WandKind kind) { kind = WandKind.Chaos; if ((Object)(object)prop == (Object)null) { return false; } NetworkIdentity componentInParent = ((Component)prop).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { return false; } if (componentInParent.assetId == 1497711432) { kind = WandKind.Chaos; return true; } if (componentInParent.assetId == 1497712210) { kind = WandKind.Frost; return true; } return false; } internal static string GetDisplayName(WandKind kind) { if (kind != WandKind.Chaos) { return FrostDisplayName; } return ChaosDisplayName; } internal static void ApplySlot(UIInventorySlot slot) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)slot == (Object)null) { return; } InventoryItem currentItem; try { currentItem = slot.CurrentItem; } catch { return; } if (((InventoryItem)(ref currentItem)).IsEmpty || !TryGetKind(((InventoryItem)(ref currentItem)).PropInstance, out var kind)) { return; } Sprite val = ((kind == WandKind.Chaos) ? _chaosIcon : _frostIcon); if ((Object)(object)val == (Object)null || SlotIconField == null) { return; } try { object? value = SlotIconField.GetValue(slot); Image val2 = (Image)((value is Image) ? value : null); if (!((Object)(object)val2 == (Object)null)) { val2.sprite = val; val2.preserveAspect = true; ((Graphic)val2).color = Color.white; ((Behaviour)val2).enabled = true; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Inventory icon apply skipped safely: " + ex.Message)); } } internal static void SetCustomVisualVisible(NetworkPuppetProp prop, bool visible) { if (!TryGetKind(prop, out var kind)) { return; } NetworkIdentity componentInParent = ((Component)prop).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { return; } string text = kind.ToString() + "_CustomVisual"; Transform transform = ((Component)componentInParent).transform; Transform val = transform.Find(text); if ((Object)(object)val == (Object)null) { Transform[] componentsInChildren = ((Component)transform).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && ((Object)val2).name == text) { val = val2; break; } } } if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf != visible) { ((Component)val).gameObject.SetActive(visible); } } internal static int FindInventorySlotIndex(NetworkPuppetProp prop) { //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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prop == (Object)null) { return -1; } UIInventorySlot[] array; try { array = Resources.FindObjectsOfTypeAll(); } catch { return -1; } foreach (UIInventorySlot val in array) { if ((Object)(object)val == (Object)null) { continue; } Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { InventoryItem currentItem; try { currentItem = val.CurrentItem; } catch { continue; } if (!((InventoryItem)(ref currentItem)).IsEmpty && !((Object)(object)((InventoryItem)(ref currentItem)).PropInstance != (Object)(object)prop)) { return GetSlotIndex(val); } } } return -1; } private static int GetSlotIndex(UIInventorySlot slot) { if ((Object)(object)slot == (Object)null) { return -1; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; Type type = ((object)slot).GetType(); string[] array = new string[5] { "SlotIndex", "slotIndex", "_slotIndex", "Index", "index" }; for (int i = 0; i < array.Length; i++) { PropertyInfo property = type.GetProperty(array[i], bindingAttr); if (property != null && property.GetIndexParameters().Length == 0) { try { if (property.GetValue(slot, null) is int result) { return result; } } catch { } } FieldInfo field = type.GetField(array[i], bindingAttr); if (!(field != null)) { continue; } try { if (!(field.GetValue(slot) is int result2)) { continue; } return result2; } catch { } } return -1; } internal static bool IsCustomVisualVisible(NetworkIdentity identity) { if ((Object)(object)identity == (Object)null || !NetworkWandRegistry.IsOurAssetIdPublic(identity.assetId)) { return true; } string text = ((identity.assetId == 1497711432) ? (WandKind.Chaos.ToString() + "_CustomVisual") : (WandKind.Frost.ToString() + "_CustomVisual")); Transform val = ((Component)identity).transform.Find(text); if ((Object)(object)val == (Object)null) { return true; } return ((Component)val).gameObject.activeSelf; } private static void RefreshVisibleSlots() { try { UIInventorySlot[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { ApplySlot(array[i]); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Inventory slot refresh skipped safely: " + ex.Message)); } } private static Sprite LoadIcon(string fileName, string spriteName) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) try { string text = Path.Combine(Paths.PluginPath, "YAPYAPExpanded", "icons", fileName); if (!File.Exists(text)) { Plugin.Log.LogWarning((object)("Inventory icon file not found: " + text)); return null; } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ((Object)val).name = spriteName + "_Texture"; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; if (!ImageConversion.LoadImage(val, array, false)) { Object.Destroy((Object)(object)val); return null; } Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)obj).name = spriteName; return obj; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Inventory icon load failed for " + fileName + ": " + ex.Message)); return null; } } } [HarmonyPatch(typeof(NetworkPuppetProp), "get_DisplayName")] internal static class ModWandDisplayNamePatch { private static void Postfix(NetworkPuppetProp __instance, ref string __result) { if (InventoryAppearance.TryGetKind(__instance, out var kind)) { __result = InventoryAppearance.GetDisplayName(kind); } } } [HarmonyPatch(typeof(NetworkPuppetProp), "ShowTooltip")] internal static class ModWandWorldTooltipPatch { private static void Prefix(NetworkPuppetProp __instance) { if (InventoryAppearance.TryGetKind(__instance, out var kind)) { ((Interactable)__instance).interactStr = InventoryAppearance.GetDisplayName(kind); } } } [HarmonyPatch(typeof(UIInventorySlot), "RefreshDisplay")] internal static class ModWandInventorySlotPatch { private static void Postfix(UIInventorySlot __instance) { InventoryAppearance.ApplySlot(__instance); } } [HarmonyPatch(typeof(NetworkPuppetWandProp), "OnEnteredInventory")] internal static class ModWandEnteredInventoryPatch { private static void Prefix(NetworkPuppetWandProp __instance) { InventoryAppearance.SetCustomVisualVisible((NetworkPuppetProp)(object)__instance, visible: false); } private static void Postfix(NetworkPuppetWandProp __instance) { if (NetworkServer.active) { WandPersistence.RequestSave(log: false); } } } [HarmonyPatch(typeof(NetworkPuppetWandProp), "OnExitedInventory")] internal static class ModWandExitedInventoryPatch { private static void Postfix(NetworkPuppetWandProp __instance) { InventoryAppearance.SetCustomVisualVisible((NetworkPuppetProp)(object)__instance, visible: true); if (NetworkServer.active) { WandPersistence.RequestSave(log: false); } } } [HarmonyPatch(typeof(NetworkPuppetWandProp), "OnPickedUp")] internal static class ModWandPickedUpPatch { private static void Postfix(NetworkPuppetWandProp __instance) { InventoryAppearance.SetCustomVisualVisible((NetworkPuppetProp)(object)__instance, visible: true); } } [HarmonyPatch(typeof(NetworkPuppetWandProp), "OnDropped")] internal static class ModWandDroppedPatch { private static void Postfix(NetworkPuppetWandProp __instance) { InventoryAppearance.SetCustomVisualVisible((NetworkPuppetProp)(object)__instance, visible: true); if (NetworkServer.active) { WandPersistence.RequestSave(log: false); } } } internal static class InventoryPersistencePatcher { private static readonly HashSet Patched = new HashSet(); internal static void Install(Harmony harmony) { if (harmony == null) { return; } try { Type type = typeof(Pawn).Assembly.GetType("YAPYAP.PawnInventory", throwOnError: false); if (type == null) { Plugin.Log.LogWarning((object)"Inventory persistence hooks: YAPYAP.PawnInventory type not found"); return; } int num = PatchNamed(harmony, type, "ServerPersistInventory", "BeforeVanillaInventoryPersist"); int num2 = PatchNamed(harmony, type, "SvDropAllItemsFromInventory", "BeforeVanillaDropAll"); Plugin.Log.LogInfo((object)("Inventory persistence hooks installed | ServerPersistInventory=" + num + " | SvDropAllItemsFromInventory=" + num2)); } catch (Exception ex) { Plugin.Log.LogError((object)("Inventory persistence hook install failed safely: " + ex)); } } private static int PatchNamed(Harmony harmony, Type type, string methodName, string prefixName) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown int num = 0; MethodInfo method = typeof(InventoryPersistencePatcher).GetMethod(prefixName, BindingFlags.Static | BindingFlags.NonPublic); if (method == null) { return 0; } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo == null) && !(methodInfo.Name != methodName) && !Patched.Contains(methodInfo)) { try { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Patched.Add(methodInfo); num++; Plugin.Log.LogInfo((object)("Inventory persistence hook active: " + type.FullName + "." + methodInfo.Name)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Inventory persistence hook skipped for " + methodName + ": " + ex.Message)); } } } return num; } private static void BeforeVanillaInventoryPersist() { WandPersistence.RequestSave(log: false); } private static void BeforeVanillaDropAll() { WandPersistence.CaptureBeforeMassInventoryDrop("PawnInventory.SvDropAllItemsFromInventory"); } } internal static class InventoryRestoreBridge { private static readonly BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static bool _metadataReady; private static Type _pawnInventoryType; private static Type _inventoryItemType; private static MethodInfo _serverTryPickupInventorySlotOnly; private static MethodInfo _serverTryPickup; private static PropertyInfo _itemsProperty; private static FieldInfo _itemsField; private static PropertyInfo _itemPropProperty; private static PropertyInfo _itemIsEmptyProperty; private static Pawn _cachedPawn; private static Component _cachedInventory; private static bool _loggedNotReady; internal static bool IsReady() { object pawnInventory = GetPawnInventory(); if (pawnInventory == null) { return false; } int num; if (GetItems(pawnInventory) != null) { if (!(_serverTryPickupInventorySlotOnly != null)) { num = ((_serverTryPickup != null) ? 1 : 0); if (num == 0) { goto IL_0034; } } else { num = 1; } goto IL_0050; } num = 0; goto IL_0034; IL_0050: return (byte)num != 0; IL_0034: if (!_loggedNotReady) { _loggedNotReady = true; Plugin.Log.LogInfo((object)"Inventory restore: waiting for YAPYAP PawnInventory to become ready"); } goto IL_0050; } internal static bool IsActuallyInInventory(GameObject obj) { if ((Object)(object)obj == (Object)null) { return false; } NetworkPuppetProp componentInChildren = obj.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { return FindActualInventorySlot(componentInChildren) >= 0; } return false; } internal static int FindActualInventorySlot(NetworkPuppetProp wantedProp) { if ((Object)(object)wantedProp == (Object)null) { return -1; } object pawnInventory = GetPawnInventory(); if (pawnInventory == null) { return -1; } if (!(GetItems(pawnInventory) is IEnumerable enumerable)) { return -1; } int num = 0; try { foreach (object item in enumerable) { NetworkPuppetProp itemProp = GetItemProp(item); if ((Object)(object)itemProp != (Object)null && (Object)(object)itemProp == (Object)(object)wantedProp) { return num; } num++; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Inventory slot lookup failed safely: " + ex.Message)); } return -1; } internal static int ResolveUsableSlot(int preferredSlot) { object pawnInventory = GetPawnInventory(); if (pawnInventory == null) { return -1; } if (!(GetItems(pawnInventory) is IEnumerable enumerable)) { return -1; } int num = -1; int num2 = 0; try { foreach (object item in enumerable) { if (IsItemEmpty(item)) { if (num2 == preferredSlot) { return num2; } if (num < 0) { num = num2; } } num2++; } return num; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Inventory empty-slot lookup failed safely: " + ex.Message)); return -1; } } internal static bool TryPlaceInInventory(GameObject obj, int preferredSlot, out int actualSlot) { actualSlot = -1; if (!NetworkServer.active || (Object)(object)obj == (Object)null) { return false; } NetworkPuppetProp componentInChildren = obj.GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { return false; } int num = FindActualInventorySlot(componentInChildren); if (num >= 0) { actualSlot = num; return true; } object pawnInventory = GetPawnInventory(); if (pawnInventory == null) { return false; } int num2 = ResolveUsableSlot(preferredSlot); if (num2 < 0) { return false; } if (InvokePickupMethod(_serverTryPickupInventorySlotOnly, pawnInventory, componentInChildren, num2)) { actualSlot = FindActualInventorySlot(componentInChildren); if (actualSlot >= 0) { return true; } } if (InvokePickupMethod(_serverTryPickup, pawnInventory, componentInChildren, num2)) { actualSlot = FindActualInventorySlot(componentInChildren); if (actualSlot >= 0) { return true; } } actualSlot = FindActualInventorySlot(componentInChildren); return actualSlot >= 0; } internal static bool TryPlaceInInventory(GameObject obj, int preferredSlot) { int actualSlot; return TryPlaceInInventory(obj, preferredSlot, out actualSlot); } private static bool InvokePickupMethod(MethodInfo method, object inventory, NetworkPuppetProp prop, int slot) { if (method == null || inventory == null || (Object)(object)prop == (Object)null) { return false; } try { if (!(method.Invoke(inventory, new object[2] { prop, slot }) is bool result)) { return true; } return result; } catch (TargetInvocationException ex) { Exception ex2 = ex.InnerException ?? ex; Plugin.Log.LogWarning((object)("Native inventory pickup failed safely: " + ex2.Message)); return false; } catch (Exception ex3) { Plugin.Log.LogWarning((object)("Native inventory pickup failed safely: " + ex3.Message)); return false; } } private static object GetPawnInventory() { EnsureMetadata(); if (_pawnInventoryType == null) { return null; } Pawn localInstance = Pawn.LocalInstance; if ((Object)(object)localInstance == (Object)null) { _cachedPawn = null; _cachedInventory = null; return null; } if ((Object)(object)_cachedPawn == (Object)(object)localInstance && (Object)(object)_cachedInventory != (Object)null) { return _cachedInventory; } _cachedPawn = localInstance; _cachedInventory = ((Component)localInstance).gameObject.GetComponent(_pawnInventoryType); return _cachedInventory; } private static object GetItems(object inventory) { if (inventory == null) { return null; } try { if (_itemsProperty != null) { return _itemsProperty.GetValue(inventory, null); } if (_itemsField != null) { return _itemsField.GetValue(inventory); } } catch { } return null; } private static NetworkPuppetProp GetItemProp(object item) { if (item == null || _itemPropProperty == null) { return null; } try { object? value = _itemPropProperty.GetValue(item, null); return (NetworkPuppetProp)((value is NetworkPuppetProp) ? value : null); } catch { return null; } } private static bool IsItemEmpty(object item) { if (item == null) { return true; } if (_itemIsEmptyProperty != null) { try { object value = _itemIsEmptyProperty.GetValue(item, null); if (value is bool) { return (bool)value; } } catch { } } return (Object)(object)GetItemProp(item) == (Object)null; } private static void EnsureMetadata() { if (_metadataReady) { return; } _metadataReady = true; try { Assembly assembly = typeof(Pawn).Assembly; _pawnInventoryType = assembly.GetType("YAPYAP.PawnInventory", throwOnError: false); _inventoryItemType = assembly.GetType("YAPYAP.InventoryItem", throwOnError: false); if (_pawnInventoryType != null) { _serverTryPickupInventorySlotOnly = _pawnInventoryType.GetMethod("ServerTryPickupInventorySlotOnly", InstanceFlags, null, new Type[2] { typeof(NetworkPuppetProp), typeof(int) }, null); _serverTryPickup = _pawnInventoryType.GetMethod("ServerTryPickup", InstanceFlags, null, new Type[2] { typeof(NetworkPuppetProp), typeof(int) }, null); _itemsProperty = _pawnInventoryType.GetProperty("Items", InstanceFlags); if (_itemsProperty == null) { _itemsField = _pawnInventoryType.GetField("inventoryItems", InstanceFlags); } } if (_inventoryItemType != null) { _itemPropProperty = _inventoryItemType.GetProperty("PropInstance", InstanceFlags); _itemIsEmptyProperty = _inventoryItemType.GetProperty("IsEmpty", InstanceFlags); } Plugin.Log.LogInfo((object)("Native inventory bridge cached | PawnInventory=" + (_pawnInventoryType != null) + " | Items=" + (_itemsProperty != null || _itemsField != null) + " | ServerTryPickupInventorySlotOnly=" + (_serverTryPickupInventorySlotOnly != null) + " | ServerTryPickup=" + (_serverTryPickup != null))); } catch (Exception ex) { Plugin.Log.LogError((object)("Native inventory bridge metadata cache failed: " + ex)); } } } internal enum WandKind { Chaos, Frost } internal static class NetworkWandRegistry { [CompilerGenerated] private static class <>O { public static SpawnHandlerDelegate <0>__SpawnChaosClient; public static UnSpawnDelegate <1>__UnspawnClient; public static SpawnHandlerDelegate <2>__SpawnFrostClient; } internal const uint ChaosAssetId = 1497711432u; internal const uint FrostAssetId = 1497712210u; private static readonly FieldInfo AssetIdField = typeof(NetworkIdentity).GetField("_assetId", BindingFlags.Instance | BindingFlags.NonPublic); private static bool _clientHandlersRegistered; private static bool _wasClientActive; private static GameObject _cachedDonor; internal static void UpdateRegistrationState() { if (!NetworkClient.active) { _clientHandlersRegistered = false; _wasClientActive = false; return; } if (!_wasClientActive) { _clientHandlersRegistered = false; _wasClientActive = true; } if (!_clientHandlersRegistered) { RegisterClientSpawnHandlers(); } } private static void RegisterClientSpawnHandlers() { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown if (AssetIdField == null) { Plugin.Log.LogError((object)"Mirror NetworkIdentity._assetId field was not found. Network test disabled."); return; } GameObject val = default(GameObject); if (NetworkClient.GetPrefab(1497711432u, ref val)) { Plugin.Log.LogError((object)("Chaos assetId collision with existing prefab: " + ((Object)val).name + " (" + 1497711432u + ")")); return; } if (NetworkClient.GetPrefab(1497712210u, ref val)) { Plugin.Log.LogError((object)("Frost assetId collision with existing prefab: " + ((Object)val).name + " (" + 1497712210u + ")")); return; } object obj = <>O.<0>__SpawnChaosClient; if (obj == null) { SpawnHandlerDelegate val2 = SpawnChaosClient; <>O.<0>__SpawnChaosClient = val2; obj = (object)val2; } object obj2 = <>O.<1>__UnspawnClient; if (obj2 == null) { UnSpawnDelegate val3 = UnspawnClient; <>O.<1>__UnspawnClient = val3; obj2 = (object)val3; } NetworkClient.RegisterSpawnHandler(1497711432u, (SpawnHandlerDelegate)obj, (UnSpawnDelegate)obj2); object obj3 = <>O.<2>__SpawnFrostClient; if (obj3 == null) { SpawnHandlerDelegate val4 = SpawnFrostClient; <>O.<2>__SpawnFrostClient = val4; obj3 = (object)val4; } object obj4 = <>O.<1>__UnspawnClient; if (obj4 == null) { UnSpawnDelegate val5 = UnspawnClient; <>O.<1>__UnspawnClient = val5; obj4 = (object)val5; } NetworkClient.RegisterSpawnHandler(1497712210u, (SpawnHandlerDelegate)obj3, (UnSpawnDelegate)obj4); _clientHandlersRegistered = true; Plugin.Log.LogInfo((object)("Registered Mirror spawn handlers: Chaos=" + 1497711432u + ", Frost=" + 1497712210u)); } private static GameObject SpawnChaosClient(SpawnMessage message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return SpawnClientVisualizedDonor(message, WandKind.Chaos); } private static GameObject SpawnFrostClient(SpawnMessage message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return SpawnClientVisualizedDonor(message, WandKind.Frost); } private static void UnspawnClient(GameObject obj) { if ((Object)(object)obj != (Object)null) { Object.Destroy((Object)(object)obj); } } private static GameObject SpawnClientVisualizedDonor(SpawnMessage message, WandKind kind) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) GameObject donor = FindDonorWand(); if ((Object)(object)donor == (Object)null) { Plugin.Log.LogError((object)("CLIENT spawn failed for " + kind.ToString() + ": vanilla wand donor not found")); return null; } GameObject visual = GetVisual(kind); if ((Object)(object)visual == (Object)null) { Plugin.Log.LogError((object)("CLIENT spawn failed for " + kind.ToString() + ": AssetBundle visual missing")); return null; } GameObject val = VanillaSpellExpansion.InstantiateDonor(() => Object.Instantiate(donor, message.position, message.rotation)); ((Object)val).name = "YAPYAPExpanded_" + kind.ToString() + "Wand_NET"; NetworkIdentity component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogError((object)"CLIENT clone has no NetworkIdentity"); Object.Destroy((Object)(object)val); return null; } SetAssetId(component, GetAssetId(kind)); ReplaceVanillaVisual(val, visual, kind); if (!CustomSpellSystem.ConfigureWand(val, kind)) { Object.Destroy((Object)(object)val); return null; } ShopEconomy.ApplyPrice(val.GetComponent()); val.SetActive(true); Plugin.Log.LogInfo((object)("CLIENT created " + kind.ToString() + " wand for assetId=" + message.assetId)); return val; } internal static GameObject CreateShopTemplate(WandKind kind, Transform inactiveParent) { GameObject donor = FindDonorWand(); if ((Object)(object)donor == (Object)null || (Object)(object)inactiveParent == (Object)null || AssetIdField == null || !CustomSpellSystem.Ready) { return null; } GameObject obj = VanillaSpellExpansion.InstantiateDonor(() => Object.Instantiate(donor, inactiveParent)); obj.SetActive(false); ((Object)obj).name = "YAPYAPExpanded_" + kind.ToString() + "_ShopTemplate"; SetAssetId(obj.GetComponent(), GetAssetId(kind)); ShopEconomy.ApplyPrice(obj.GetComponent()); return obj; } internal static GameObject SpawnServerAt(WandKind kind, Vector3 position, Quaternion rotation, bool restoredFromSave) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_000f: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { Plugin.Log.LogWarning((object)("Cannot spawn " + kind.ToString() + ": NetworkServer is not active.")); return null; } if (AssetIdField == null) { Plugin.Log.LogError((object)"Cannot spawn: NetworkIdentity._assetId field was not found"); return null; } GameObject donor = FindDonorWand(); if ((Object)(object)donor == (Object)null) { Plugin.Log.LogError((object)("Cannot spawn " + kind.ToString() + ": vanilla NetworkPuppetWandProp donor not found")); return null; } GameObject visual = GetVisual(kind); if ((Object)(object)visual == (Object)null) { Plugin.Log.LogError((object)("Cannot spawn " + kind.ToString() + ": visual prefab missing from AssetBundle")); return null; } GameObject val = VanillaSpellExpansion.InstantiateDonor(() => Object.Instantiate(donor, position, rotation)); ((Object)val).name = "YAPYAPExpanded_" + kind.ToString() + "Wand_NET"; NetworkIdentity component = val.GetComponent(); NetworkPuppetWandProp componentInChildren = val.GetComponentInChildren(true); if ((Object)(object)component == (Object)null || (Object)(object)componentInChildren == (Object)null) { Plugin.Log.LogError((object)"SERVER donor clone is missing NetworkIdentity or NetworkPuppetWandProp"); Object.Destroy((Object)(object)val); return null; } uint assetId = GetAssetId(kind); SetAssetId(component, assetId); ReplaceVanillaVisual(val, visual, kind); if (!CustomSpellSystem.ConfigureWand(val, kind)) { Object.Destroy((Object)(object)val); return null; } ShopEconomy.ApplyPrice(val.GetComponent()); val.SetActive(true); NetworkServer.Spawn(val, (NetworkConnectionToClient)null); Plugin.Log.LogInfo((object)("SERVER spawned " + kind.ToString() + " wand | custom assetId=" + component.assetId + " | donor='" + ((Object)donor).name + "' | donorSpell=" + (((Object)(object)componentInChildren.Spell != (Object)null) ? ((object)componentInChildren.Spell).GetType().FullName : "NULL") + (restoredFromSave ? " | RESTORED" : ""))); return val; } internal static void ResetSessionCache() { _cachedDonor = null; } private static GameObject FindDonorWand() { if ((Object)(object)_cachedDonor != (Object)null) { return _cachedDonor; } NetworkManager singleton = NetworkManager.singleton; if ((Object)(object)singleton == (Object)null || singleton.spawnPrefabs == null) { return null; } foreach (GameObject spawnPrefab in singleton.spawnPrefabs) { if (IsValidDonor(spawnPrefab) && ((Object)spawnPrefab).name.IndexOf("PropWandOfAstral", StringComparison.OrdinalIgnoreCase) >= 0) { _cachedDonor = spawnPrefab; Plugin.Log.LogInfo((object)("Selected vanilla wand donor: " + ((Object)spawnPrefab).name)); return _cachedDonor; } } foreach (GameObject spawnPrefab2 in singleton.spawnPrefabs) { if (IsValidDonor(spawnPrefab2) && ((Object)spawnPrefab2).name.IndexOf("wand", StringComparison.OrdinalIgnoreCase) >= 0) { _cachedDonor = spawnPrefab2; Plugin.Log.LogInfo((object)("Selected fallback wand donor: " + ((Object)spawnPrefab2).name)); return _cachedDonor; } } return null; } private static bool IsValidDonor(GameObject prefab) { if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent() != (Object)null && (Object)(object)prefab.GetComponentInChildren(true) != (Object)null) { return CustomSpellSystem.CanConfigure(prefab); } return false; } private static void SetAssetId(NetworkIdentity identity, uint assetId) { AssetIdField.SetValue(identity, assetId); } private static uint GetAssetId(WandKind kind) { if (kind != WandKind.Chaos) { return 1497712210u; } return 1497711432u; } private static bool IsOurAssetId(uint assetId) { if (assetId != 1497711432) { return assetId == 1497712210; } return true; } internal static bool IsOurAssetIdPublic(uint assetId) { return IsOurAssetId(assetId); } private static GameObject GetVisual(WandKind kind) { if (kind != WandKind.Chaos) { return AssetLoader.FrostVisual; } return AssetLoader.ChaosVisual; } private static void ReplaceVanillaVisual(GameObject wandRoot, GameObject visualPrefab, WandKind kind) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) Bounds result; bool flag = TryGetVisualBoundsInRoot(wandRoot, null, out result); MeshRenderer[] componentsInChildren = wandRoot.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Renderer)componentsInChildren[i]).enabled = false; } SkinnedMeshRenderer[] componentsInChildren2 = wandRoot.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Renderer)componentsInChildren2[i]).enabled = false; } GameObject val = Object.Instantiate(visualPrefab); ((Object)val).name = kind.ToString() + "_CustomVisual"; val.transform.SetParent(wandRoot.transform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; val.SetActive(true); Collider[] componentsInChildren3 = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.Destroy((Object)(object)componentsInChildren3[i]); } Rigidbody[] componentsInChildren4 = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren4.Length; i++) { Object.Destroy((Object)(object)componentsInChildren4[i]); } NetworkBehaviour[] componentsInChildren5 = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren5.Length; i++) { Object.Destroy((Object)(object)componentsInChildren5[i]); } NetworkIdentity[] componentsInChildren6 = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren6.Length; i++) { Object.Destroy((Object)(object)componentsInChildren6[i]); } if (flag) { AutoAlignVisual(wandRoot, val, result, kind); } else { Plugin.Log.LogWarning((object)("Visual auto-align: donor bounds unavailable for " + kind)); } } private static void AutoAlignVisual(GameObject wandRoot, GameObject visual, Bounds donorBounds, WandKind kind) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: 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_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[16] { new Vector3(90f, 0f, 0f), new Vector3(-90f, 0f, 0f), new Vector3(0f, 0f, 0f), new Vector3(0f, 90f, 0f), new Vector3(0f, -90f, 0f), new Vector3(0f, 0f, 90f), new Vector3(0f, 0f, -90f), new Vector3(90f, 90f, 0f), new Vector3(90f, -90f, 0f), new Vector3(-90f, 90f, 0f), new Vector3(-90f, -90f, 0f), new Vector3(0f, 180f, 0f), new Vector3(180f, 0f, 0f), new Vector3(0f, 0f, 180f), new Vector3(90f, 180f, 0f), new Vector3(-90f, 180f, 0f) }; float bestScore = float.MaxValue; Quaternion localRotation = Quaternion.identity; float num = 1f; bool flag = false; for (int i = 0; i < array.Length; i++) { visual.transform.localPosition = Vector3.zero; visual.transform.localScale = Vector3.one; visual.transform.localRotation = Quaternion.Euler(array[i]); if (!TryGetVisualBoundsInRoot(wandRoot, visual, out var result)) { continue; } float num2 = Mathf.Max(((Bounds)(ref result)).size.x, Mathf.Max(((Bounds)(ref result)).size.y, ((Bounds)(ref result)).size.z)); float num3 = Mathf.Max(((Bounds)(ref donorBounds)).size.x, Mathf.Max(((Bounds)(ref donorBounds)).size.y, ((Bounds)(ref donorBounds)).size.z)); if (!(num2 < 0.0001f) && !(num3 < 0.0001f)) { float num4 = num3 / num2; Vector3 val = ((Bounds)(ref result)).size * num4; float num5 = AxisScore(val.x, ((Bounds)(ref donorBounds)).size.x) + AxisScore(val.y, ((Bounds)(ref donorBounds)).size.y) + AxisScore(val.z, ((Bounds)(ref donorBounds)).size.z); if (IsBetterAlignment(num5, bestScore)) { bestScore = num5; localRotation = visual.transform.localRotation; num = num4; flag = true; } } } if (!flag) { Plugin.Log.LogWarning((object)("Visual auto-align failed for " + kind)); return; } visual.transform.localRotation = localRotation; visual.transform.localScale = Vector3.one * num; visual.transform.localPosition = Vector3.zero; if (TryGetVisualBoundsInRoot(wandRoot, visual, out var result2)) { Vector3 val2 = ((Bounds)(ref donorBounds)).center - ((Bounds)(ref result2)).center; Transform transform = visual.transform; transform.localPosition += val2; } Plugin.Log.LogInfo((object)("Visual aligned " + kind.ToString() + " | rotation=" + ((object)visual.transform.localEulerAngles/*cast due to .constrained prefix*/).ToString() + " | scale=" + num.ToString("F3") + " | donorSize=" + ((object)((Bounds)(ref donorBounds)).size/*cast due to .constrained prefix*/).ToString())); } private static float AxisScore(float a, float b) { a = Mathf.Max(a, 0.0001f); b = Mathf.Max(b, 0.0001f); return Mathf.Abs(Mathf.Log(a / b)); } internal static bool IsBetterAlignment(float score, float bestScore) { return score < bestScore - 0.0001f; } internal static Bounds TransformMeshBounds(Bounds bounds, Matrix4x4 meshToRoot) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_006e: Unknown result type (might be due to invalid IL or missing references) Vector3 min = ((Bounds)(ref bounds)).min; Vector3 max = ((Bounds)(ref bounds)).max; Bounds result = default(Bounds); ((Bounds)(ref result))..ctor(((Matrix4x4)(ref meshToRoot)).MultiplyPoint3x4(min), Vector3.zero); Vector3 val = default(Vector3); for (int i = 1; i < 8; i++) { ((Vector3)(ref val))..ctor(((i & 1) == 0) ? min.x : max.x, ((i & 2) == 0) ? min.y : max.y, ((i & 4) == 0) ? min.z : max.z); ((Bounds)(ref result)).Encapsulate(((Matrix4x4)(ref meshToRoot)).MultiplyPoint3x4(val)); } return result; } private static bool TryGetVisualBoundsInRoot(GameObject root, GameObject onlyInside, out Bounds result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) result = default(Bounds); bool flag = false; Renderer[] componentsInChildren = (((Object)(object)onlyInside != (Object)null) ? onlyInside : root).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || (!(val is MeshRenderer) && !(val is SkinnedMeshRenderer))) { continue; } SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null); Bounds bounds; if (val2 != null) { bounds = ((Renderer)val2).localBounds; } else { MeshFilter component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null) { continue; } bounds = component.sharedMesh.bounds; } Matrix4x4 val3 = Matrix4x4.identity; Transform val4 = ((Component)val).transform; while ((Object)(object)val4 != (Object)null && (Object)(object)val4 != (Object)(object)root.transform) { val3 = Matrix4x4.TRS(val4.localPosition, val4.localRotation, val4.localScale) * val3; val4 = val4.parent; } if (!((Object)(object)val4 != (Object)(object)root.transform)) { Bounds val5 = TransformMeshBounds(bounds, val3); if (!flag) { result = val5; flag = true; } else { ((Bounds)(ref result)).Encapsulate(((Bounds)(ref val5)).min); ((Bounds)(ref result)).Encapsulate(((Bounds)(ref val5)).max); } } } return flag; } } [BepInPlugin("com.danya.yapyapexpanded", "YAPYAP Expanded", "0.13.0")] public sealed class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; private SpellBook _spellBook; private void Awake() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"YAPYAP Expanded 0.13.0: Frost and Chaos spell schools loaded"); AssetLoader.Load(); InventoryAppearance.Initialize(); Harmony harmony = new Harmony("com.danya.yapyapexpanded.v0130"); ModLocalization.Install(((BaseUnityPlugin)this).Config, harmony); ((Component)this).gameObject.AddComponent(); ModMenuInput.Install(((BaseUnityPlugin)this).Config); ((Component)this).gameObject.AddComponent(); VanillaSpellExpansion.Install(harmony); ((Component)this).gameObject.AddComponent(); VoiceVocabularyPatcher.PrepareFilesAndInstall(harmony); RollOverlay.Initialize(); WorldContextPatcher.Install(harmony); InventoryPersistencePatcher.Install(harmony); CustomSpellPatcher.Install(harmony); SpawnDirector.Install(); ScaleBoostScore.Install(); ShopEconomy.Install(); WandLootBalance.Install(); CharacterUpgrades.Install(new Harmony("com.danya.yapyapexpanded.upgrades.v0130")); ((Component)this).gameObject.AddComponent(); ((Component)this).gameObject.AddComponent(); _spellBook = ((Component)this).gameObject.AddComponent(); PatchClassSafe(harmony, typeof(ModWandDisplayNamePatch)); PatchClassSafe(harmony, typeof(ModWandWorldTooltipPatch)); PatchClassSafe(harmony, typeof(ModWandInventorySlotPatch)); PatchClassSafe(harmony, typeof(ModWandEnteredInventoryPatch)); PatchClassSafe(harmony, typeof(ModWandExitedInventoryPatch)); PatchClassSafe(harmony, typeof(ModWandPickedUpPatch)); PatchClassSafe(harmony, typeof(ModWandDroppedPatch)); Log.LogInfo((object)"YAPYAP Expanded Beta 1: F4 = merchant upgrades; F5 = spell book."); } private static void PatchClassSafe(Harmony harmony, Type patchType) { try { harmony.CreateClassProcessor(patchType).Patch(); Log.LogInfo((object)("Harmony patch active: " + patchType.Name)); } catch (Exception ex) { Log.LogError((object)("Harmony patch failed for " + patchType.Name + ": " + ex)); } } private void Update() { NetworkWandRegistry.UpdateRegistrationState(); WandPersistence.Update(); if (Input.GetKeyDown((KeyCode)286) && (Object)(object)_spellBook != (Object)null) { _spellBook.Toggle(); } if (ModMenuInput.OpenPressed && ModMenuInput.CanOpen && !UpgradeMenu.TryOpenNearMerchant()) { _spellBook?.Toggle(); } } } internal static class RollOverlay { private sealed class DiceGui : MonoBehaviour { internal Texture2D[] faces; private Coroutine _routine; private bool _visible; private int _face = 1; private float _angle; private float _alpha = 1f; private bool _settled; internal void Play(int finalFace) { if (faces != null && faces.Length >= 6) { if (_routine != null) { ((MonoBehaviour)this).StopCoroutine(_routine); } _routine = ((MonoBehaviour)this).StartCoroutine(Animate(finalFace)); } } private IEnumerator Animate(int finalFace) { _visible = true; _settled = false; _alpha = 1f; _angle = 0f; float elapsed = 0f; float spinTime = 0.68f; float nextFace = 0f; while (elapsed < spinTime) { elapsed += Time.unscaledDeltaTime; if (elapsed >= nextFace) { _face = Random.Range(1, 7); nextFace = elapsed + 0.055f; } _angle = Mathf.Lerp(0f, 540f, elapsed / spinTime); yield return null; } _face = finalFace; _angle = 0f; _settled = true; yield return (object)new WaitForSecondsRealtime(1.2f); float fade = 0f; while (fade < 0.2f) { fade += Time.unscaledDeltaTime; _alpha = 1f - Mathf.Clamp01(fade / 0.2f); yield return null; } _visible = false; _alpha = 0f; _routine = null; } private void OnGUI() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if (_visible && faces != null && _face >= 1 && _face <= 6) { Vector2 val = FindPositionNearInventory(36f); Matrix4x4 matrix = GUI.matrix; Color color = GUI.color; GUI.color = new Color(1f, 1f, 1f, _alpha); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(val.x + 18f, val.y + 18f); GUIUtility.RotateAroundPivot(_angle, val2); GUI.DrawTexture(new Rect(val.x, val.y, 36f, 36f), (Texture)(object)faces[_face - 1], (ScaleMode)2, true); GUI.matrix = matrix; if (_settled) { GUIStyle val3 = new GUIStyle(GUI.skin.label); val3.alignment = (TextAnchor)4; val3.fontSize = 14; GUI.Label(new Rect(Mathf.Clamp(val.x - 82f, 0f, Mathf.Max(0f, (float)Screen.width - 200f)), val.y - 28f, 200f, 25f), Loc.Text("die." + _face), val3); } GUI.color = color; } } private static Vector2 FindPositionNearInventory(float size) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) UIInventorySlot[] array = Object.FindObjectsByType((FindObjectsSortMode)0); Vector3 val = Vector3.zero; bool flag = false; foreach (UIInventorySlot val2 in array) { if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy) { continue; } Transform transform = ((Component)val2).transform; RectTransform val3 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (!((Object)(object)val3 == (Object)null)) { Vector3 position = ((Transform)val3).position; if (!(position.y > (float)Screen.height * 0.55f) && (!flag || position.x > val.x)) { val = position; flag = true; } } } if (flag) { float num = val.x + 26f; float num2 = (float)Screen.height - val.y - size * 0.5f; return new Vector2(num, num2); } return new Vector2((float)Screen.width * 0.5f + 90f, (float)Screen.height - 105f); } } private static DiceGui _gui; private static Texture2D[] _faces; private static bool _initialized; internal static void Initialize() { if (!_initialized) { _initialized = true; EnsureCreated(); } } internal static void ShowRoll(int finalFace) { EnsureCreated(); if (!((Object)(object)_gui == (Object)null)) { _gui.Play(Mathf.Clamp(finalFace, 1, 6)); } } private static void EnsureCreated() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown if (!((Object)(object)_gui != (Object)null)) { _faces = (Texture2D[])(object)new Texture2D[6]; for (int i = 0; i < 6; i++) { _faces[i] = BuildFaceTexture(i + 1); } GameObject val = new GameObject("YAPYAPExpanded_TinyDiceGUI"); Object.DontDestroyOnLoad((Object)val); _gui = val.AddComponent(); _gui.faces = _faces; } } private static Texture2D BuildFaceTexture(int face) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); ((Object)val).name = "YAPYAPExpanded_DiePips_" + face; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; Color val2 = default(Color); ((Color)(ref val2))..ctor(0f, 0f, 0f, 0f); Color val3 = default(Color); ((Color)(ref val3))..ctor(0.97f, 0.97f, 0.97f, 1f); Color val4 = default(Color); ((Color)(ref val4))..ctor(0.08f, 0.08f, 0.08f, 1f); Color color = default(Color); ((Color)(ref color))..ctor(0.04f, 0.04f, 0.04f, 1f); for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { val.SetPixel(j, i, val2); } } for (int k = 4; k < 60; k++) { for (int l = 4; l < 60; l++) { bool flag = l < 8 || k < 8 || l >= 56 || k >= 56; val.SetPixel(l, k, flag ? val4 : val3); } } int cx = 19; int cx2 = 32; int cx3 = 45; int cy = 45; int cy2 = 32; int cy3 = 19; if (face == 1 || face == 3 || face == 5) { DrawPip(val, cx2, cy2, 4, color); } if (face >= 2) { DrawPip(val, cx, cy, 4, color); DrawPip(val, cx3, cy3, 4, color); } if (face >= 4) { DrawPip(val, cx3, cy, 4, color); DrawPip(val, cx, cy3, 4, color); } if (face == 6) { DrawPip(val, cx, cy2, 4, color); DrawPip(val, cx3, cy2, 4, color); } val.Apply(false, false); return val; } private static void DrawPip(Texture2D tex, int cx, int cy, int radius, Color color) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) int num = radius * radius; for (int i = -radius; i <= radius; i++) { for (int j = -radius; j <= radius; j++) { if (j * j + i * i <= num) { tex.SetPixel(cx + j, cy + i, color); } } } } } internal static class ShopEconomy { private sealed class Stock { internal GameObject Templates; internal Section Section; internal Pool[] OriginalPool; internal bool Ready; } private const BindingFlags Instance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static readonly Dictionary OriginalPrices = new Dictionary(); private static readonly ConditionalWeakTable Stocks = new ConditionalWeakTable(); private static FieldInfo WandSection; private static FieldInfo Listings; private static MethodInfo SetPurchasable; private static bool ready; internal static void Install() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Harmony val = new Harmony("com.danya.yapyapexpanded.shop.v080"); try { WandSection = typeof(Shop).GetField("wandSection", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException("Shop.wandSection"); Listings = typeof(Shop).GetField("allListings", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException("Shop.allListings"); SetPurchasable = typeof(Shop).GetMethod("SetUpItemPurchasable", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMethodException("Shop.SetUpItemPurchasable"); Hook(val, "Awake", null, "Awake"); Hook(val, "OnStartServer", "Prepare"); Hook(val, "Restock", "Prepare"); Hook(val, "SpawnListing", "SpawnListing"); Hook(val, "TryRestoreShop", null, "Restore"); Hook(val, "SetUpItemPurchasable", "PricePurchasable"); Hook(val, "GetSellPrice", "PriceSell"); Hook(val, "PurchaseItem", null, "Purchased"); Hook(val, "OnTrySellItem", null, "Sold"); Hook(val, "OnDestroy", "Destroy"); ready = true; Plugin.Log.LogInfo((object)"Shop economy ready: vanilla wand prices x4 (max 200), Frost=160, Chaos=180."); } catch (Exception ex) { ready = false; val.UnpatchSelf(); Plugin.Log.LogError((object)("Shop integration disabled: " + ex)); } } private static void Hook(Harmony harmony, string name, string prefix = null, string postfix = null) { MethodInfo methodInfo = typeof(Shop).GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMethodException("Shop." + name); harmony.Patch((MethodBase)methodInfo, Patch(prefix), Patch(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); static HarmonyMethod Patch(string method) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown if (method != null) { return new HarmonyMethod(typeof(ShopEconomy).GetMethod(method, BindingFlags.Static | BindingFlags.NonPublic)); } return null; } } internal static bool IsPricedWand(NetworkPuppetProp prop) { if ((Object)(object)prop == (Object)null) { return false; } NetworkIdentity component = ((Component)prop).GetComponent(); if ((Object)(object)component == (Object)null) { return false; } if (ShopPrices.TryCustom(component.assetId, out var _)) { return true; } if (prop is NetworkPuppetWandProp) { return ShopPrices.IsWandName(((Object)prop).name); } return false; } internal static int EffectiveWandPrice(NetworkPuppetProp prop) { if (!IsPricedWand(prop)) { if (!((Object)(object)prop != (Object)null)) { return 0; } return prop.purchasePrice; } NetworkIdentity component = ((Component)prop).GetComponent(); if (ShopPrices.TryCustom(component.assetId, out var kind)) { if (kind != WandKind.Frost) { return 180; } return 160; } if (!OriginalPrices.TryGetValue(component.assetId, out var value)) { value = prop.purchasePrice; OriginalPrices[component.assetId] = value; Plugin.Log.LogInfo((object)("WAND PRICE " + ((Object)prop).name + " | " + value + " -> " + ShopPrices.Vanilla(value))); } return ShopPrices.Vanilla(value); } internal static void ApplyPrice(NetworkPuppetProp prop) { if ((Object)(object)prop == (Object)null) { return; } NetworkIdentity component = ((Component)prop).GetComponent(); if ((Object)(object)component == (Object)null) { return; } if (!IsPricedWand(prop)) { if (OriginalPrices.TryGetValue(component.assetId, out var value)) { prop.purchasePrice = value; } } else { prop.purchasePrice = EffectiveWandPrice(prop); } } private static void Awake(Shop __instance) { if (!ready) { return; } NetworkManager singleton = NetworkManager.singleton; if ((Object)(object)singleton != (Object)null && singleton.spawnPrefabs != null) { foreach (GameObject spawnPrefab in singleton.spawnPrefabs) { if ((Object)(object)spawnPrefab != (Object)null) { ApplyPrice(spawnPrefab.GetComponent()); } } } object? value = WandSection.GetValue(__instance); Section val = (Section)((value is Section) ? value : null); if (val?.propPool == null) { return; } Pool[] propPool = val.propPool; foreach (Pool val2 in propPool) { if (val2 != null) { ApplyPrice(val2.prop); } } } private static void Prepare(Shop __instance) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown if (!ready || !NetworkServer.active) { return; } Awake(__instance); Stock value = Stocks.GetValue(__instance, (Shop _) => new Stock()); if (value.Ready) { return; } object? value2 = WandSection.GetValue(__instance); Section val = (Section)((value2 is Section) ? value2 : null); if (val?.propPool == null) { return; } GameObject val2 = new GameObject("YAPYAPExpanded_ShopTemplates"); val2.SetActive(false); try { GameObject val3 = NetworkWandRegistry.CreateShopTemplate(WandKind.Frost, val2.transform); GameObject val4 = NetworkWandRegistry.CreateShopTemplate(WandKind.Chaos, val2.transform); if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null) { throw new InvalidOperationException("Custom wand donor or spell hooks not ready"); } List list = new List(val.propPool); list.Add(new Pool { prop = val3.GetComponent(), weight = 1f }); list.Add(new Pool { prop = val4.GetComponent(), weight = 1f }); value.Section = val; value.OriginalPool = val.propPool; value.Templates = val2; val.propPool = list.ToArray(); value.Ready = true; Plugin.Log.LogInfo((object)"SHOP: Frost and Chaos added to normal wand stock pool."); } catch (Exception ex) { Object.Destroy((Object)(object)val2); Plugin.Log.LogError((object)("Custom shop stock not ready; will retry on restock: " + ex.Message)); } } private static bool SpawnListing(Shop __instance, int __0, NetworkPuppetProp __1) { if (!ready || !NetworkServer.active || (Object)(object)__1 == (Object)null) { return true; } NetworkIdentity component = ((Component)__1).GetComponent(); if ((Object)(object)component == (Object)null || !ShopPrices.TryCustom(component.assetId, out var kind)) { return true; } SpawnCustom(__instance, __0, kind); return false; } private static void SpawnCustom(Shop shop, int index, WandKind kind) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) ShopListing[] array = (ShopListing[])Listings.GetValue(shop); if (index < 0 || index >= array.Length || index >= shop.ListingObjectNetIds.Count || (Object)(object)array[index] == (Object)null) { return; } uint num = shop.ListingObjectNetIds[index]; if (num != 0 && NetworkServer.spawned.ContainsKey(num)) { return; } Transform point = array[index].point; GameObject val = NetworkWandRegistry.SpawnServerAt(kind, point.position, point.rotation, restoredFromSave: false); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Failed to spawn shop wand " + kind); } try { NetworkPuppetProp component = val.GetComponent(); if ((Object)(object)component == (Object)null) { throw new MissingComponentException("Custom wand has no root NetworkPuppetProp"); } Bounds worldBounds = Utility.GetWorldBounds(val.transform, false); Transform transform = val.transform; transform.position += Vector3.up * (point.position.y - ((Bounds)(ref worldBounds)).min.y); ApplyPrice(component); SetPurchasable.Invoke(shop, new object[2] { component, true }); shop.ListingObjectNetIds[index] = ((NetworkBehaviour)component).netId; Plugin.Log.LogInfo((object)("SHOP LISTING " + index + " | " + kind.ToString() + " | price=" + component.purchasePrice)); } catch { NetworkServer.Destroy(val); throw; } } private static void Restore(Shop __instance, bool __result) { SaveManager val = default(SaveManager); string text = default(string); if (!ready || !NetworkServer.active || !__result || !Service.Get(ref val) || !val.TryGetString("GAME.SHOP_ACTIVE", ref text) || string.IsNullOrEmpty(text)) { return; } ShopListing[] array = (ShopListing[])Listings.GetValue(__instance); string[] array2 = text.Split(','); for (int i = 0; i < array2.Length; i++) { if (ShopPrices.TrySavedListing(array2[i], array.Length, out var index, out var kind)) { SpawnCustom(__instance, index, kind); } } } private static void PricePurchasable(NetworkPuppetProp __0) { if (ready) { ApplyPrice(__0); } } private static void PriceSell(NetworkPuppetProp __0) { if (ready) { ApplyPrice(__0); } } private static void Purchased(Interactable __0) { if (ready && NetworkServer.active) { NetworkPuppetProp val = (NetworkPuppetProp)(object)((__0 is NetworkPuppetProp) ? __0 : null); if (val != null && !val.IsShopItem) { WandPersistence.RequestSave(log: true); } } } private static void Sold() { if (ready && NetworkServer.active) { WandPersistence.SaveNow(log: true, allowEmpty: true); } } private static void Destroy(Shop __instance) { if (Stocks.TryGetValue(__instance, out var value)) { if (value.Ready && value.Section != null) { value.Section.propPool = value.OriginalPool; } if ((Object)(object)value.Templates != (Object)null) { Object.Destroy((Object)(object)value.Templates); } Stocks.Remove(__instance); } } } internal static class ShopPrices { internal const int Frost = 160; internal const int Chaos = 180; internal static bool IsWandName(string name) { if (!string.IsNullOrEmpty(name)) { return name.IndexOf("wand", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } internal static int Vanilla(int original) { if (original > 0) { return (int)Math.Min(200L, Math.Max(40L, (long)original * 4L)); } return 0; } internal static bool TryCustom(uint assetId, out WandKind kind) { kind = WandKind.Chaos; if (assetId == 1497711432) { return true; } kind = WandKind.Frost; return assetId == 1497712210; } internal static bool TrySavedListing(string record, int listingCount, out int index, out WandKind kind) { index = -1; kind = WandKind.Chaos; if (string.IsNullOrEmpty(record)) { return false; } string[] array = record.Split(':'); if (array.Length != 3 || array[2] != "0" || !int.TryParse(array[0], out index) || index < 0 || index >= listingCount) { return false; } uint assetId = default(uint); if (PropPersistence.TryParseAssetId(array[1], ref assetId)) { return TryCustom(assetId, out kind); } return false; } } internal sealed class SlipperySurface : MonoBehaviour { private readonly Dictionary originals = new Dictionary(); private readonly Dictionary momentum = new Dictionary(); private PhysicsMaterial slippery; private static readonly PropertyInfo BodyProperty = AccessTools.Property(typeof(BaseControllerComponent), "Rigidbody"); internal static void Install(Harmony harmony) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown string[] array = new string[2] { "ApplyForce", "ApplyForceAtPosition" }; foreach (string text in array) { harmony.Patch((MethodBase)AccessTools.Method(typeof(BaseControllerComponent), text, (Type[])null, (Type[])null), new HarmonyMethod(typeof(SlipperySurface), "MovementForce", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static void MovementForce(BaseControllerComponent __instance, ref Vector3 __0) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (__instance is ControllerMovementComponent) { object? value = BodyProperty.GetValue(__instance); Rigidbody val = (Rigidbody)((value is Rigidbody) ? value : null); if (!((Object)(object)val == (Object)null) && Contains(val.position)) { Vector3 val2 = Vector3.ClampMagnitude(new Vector3(__0.x, 0f, __0.z) * 0.06f, val.mass * 1.8f); __0.x = val2.x; __0.z = val2.z; } } } private static IEnumerable Centers() { double now = NetworkTime.time; if (NetworkServer.active) { foreach (ExtraZone item in ExtraZone.Active) { if ((Object)(object)item != (Object)null && (Object)(object)item.Spell != (Object)null && item.Definition.Id == ExtraId.SlipperyYuk && item.Life.Alive(now)) { yield return item.A; } } } else { if (!NetworkClient.active) { yield break; } foreach (ExtraVisual item2 in ExtraVisual.Active) { if ((Object)(object)item2 != (Object)null && (Object)(object)item2.Spell != (Object)null && item2.Spell.Definition.Id == ExtraId.SlipperyYuk && now < item2.Expires) { yield return ((Component)item2).transform.position; } } } } internal static bool Contains(Vector3 point) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) foreach (Vector3 item in Centers()) { if (ExtraRules.InPuddle(point, item, 2.3f)) { return true; } } return false; } private void FixedUpdate() { try { Tick(); } catch (Exception ex) { Restore(); Plugin.Log.LogWarning((object)("Slippery surface restored after error: " + ex.Message)); } } private void Tick() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); Collider[] array; foreach (Vector3 item in Centers()) { array = Physics.OverlapSphere(item + Vector3.up * 0.6f, 2.6f, -1, (QueryTriggerInteraction)1); foreach (Collider val in array) { Rigidbody attachedRigidbody = val.attachedRigidbody; if ((Object)(object)attachedRigidbody != (Object)null && !attachedRigidbody.isKinematic && ExtraRules.InPuddle(attachedRigidbody.position, item, 2.3f)) { NetworkPuppetProp componentInParent = ((Component)attachedRigidbody).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (componentInParent.IsShopItem || (int)componentInParent.CurrentState.state != 0)) { continue; } hashSet.Add(val); if (!originals.ContainsKey(val)) { originals.Add(val, val.sharedMaterial); if ((Object)(object)slippery == (Object)null) { slippery = new PhysicsMaterial("YAPYAPExpanded_Slippery") { staticFriction = 0f, dynamicFriction = 0f, bounciness = 0f, frictionCombine = (PhysicsMaterialCombine)2, bounceCombine = (PhysicsMaterialCombine)2 }; } val.sharedMaterial = slippery; } } if (NetworkServer.active) { NpcBehaviour componentInParent2 = ((Component)val).GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null && !componentInParent2.IsKilled && (Object)(object)componentInParent2.Agent != (Object)null && ((Behaviour)componentInParent2.Agent).enabled && componentInParent2.Agent.isOnNavMesh && ExtraRules.InPuddle(((Component)componentInParent2.Agent).transform.position, item, 2.3f)) { hashSet2.Add(componentInParent2.Agent); } } } } array = originals.Keys.ToArray(); foreach (Collider val2 in array) { if ((Object)(object)val2 == (Object)null || !hashSet.Contains(val2)) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMaterial == (Object)(object)slippery) { val2.sharedMaterial = originals[val2]; } originals.Remove(val2); } } foreach (NavMeshAgent item2 in hashSet2) { if (!momentum.TryGetValue(item2, out var value)) { value = item2.velocity; } Vector3 velocity = item2.velocity; velocity.y = 0f; value = Vector3.MoveTowards(value, velocity, 1.4f * Time.fixedDeltaTime); Vector3 val3 = Vector3.ClampMagnitude(value - velocity, 3f); item2.Move(val3 * Time.fixedDeltaTime); momentum[item2] = value; } NavMeshAgent[] array2 = momentum.Keys.ToArray(); foreach (NavMeshAgent val4 in array2) { if ((Object)(object)val4 == (Object)null || !hashSet2.Contains(val4)) { momentum.Remove(val4); } } } private void Restore() { foreach (KeyValuePair original in originals) { if ((Object)(object)original.Key != (Object)null && (Object)(object)original.Key.sharedMaterial == (Object)(object)slippery) { original.Key.sharedMaterial = original.Value; } } originals.Clear(); momentum.Clear(); } private void OnDisable() { Restore(); } private void OnDestroy() { Restore(); if ((Object)(object)slippery != (Object)null) { Object.Destroy((Object)(object)slippery); } } } internal static class SpawnBalance { internal static double HealthMultiplier(int level) { if (level <= 1) { return 1.0; } return level switch { 2 => 1.15, 3 => 1.3, 4 => 1.5, _ => Math.Min(3.0, 1.75 + 0.175 * (double)(level - 5)), }; } internal static double FrequencyMultiplier(int level) { return 1.0 + Math.Min(0.75, (double)Math.Max(0, level - 1) * 0.09); } internal static double CountMultiplier(int level) { return 1.0 + Math.Min(0.5, (double)Math.Max(0, level - 1) * 0.06); } internal static double PowerMultiplier(int level) { return 1.0 + Math.Min(1.0, (double)Math.Max(0, level - 1) * 0.12); } internal static double TierWeight(int level, int tier) { return 1.0 + Math.Min(1.5, (double)Math.Max(0, level - 1) * 0.12 * (double)Math.Max(0, tier - 1)); } internal static int ScaleHealth(int baseline, int level) { return Math.Max(1, (int)Math.Min(2147483647.0, Math.Round((double)baseline * HealthMultiplier(level), MidpointRounding.AwayFromZero))); } internal static int ActiveLimit(int baseline, int level) { return Math.Max(1, (int)Math.Round((double)Math.Max(1, baseline) * CountMultiplier(level), MidpointRounding.AwayFromZero)); } internal static double SafeDistance(double configured, double groupRadius) { return Math.Max(20.0, configured) + Math.Max(0.0, groupRadius) + 5.0; } internal static int GroupCount(int requested, int live, int limit) { return Math.Max(0, Math.Min(requested, limit - live)); } } internal static class SpawnDirector { private sealed class Settings { internal float Interval; internal float Distance; internal float Despawn; internal int Quota = -1; internal readonly Dictionary OriginalLimits = new Dictionary(); } private sealed class HealthState { internal int Baseline; internal int Level; internal bool ServerApplied; } private const BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static readonly ConditionalWeakTable SettingsBySpawner = new ConditionalWeakTable(); private static readonly ConditionalWeakTable HealthStates = new ConditionalWeakTable(); private static FieldInfo Interval; private static FieldInfo Prefabs; private static FieldInfo Instances; private static FieldInfo Counts; private static FieldInfo Power; private static FieldInfo Points; private static FieldInfo Distance; private static FieldInfo Despawn; private static FieldInfo NextSpawnTimes; private static FieldInfo InfoNpc; private static FieldInfo InfoCount; private static FieldInfo MaxHealth; private static bool ready; internal static int Level { get { DungeonManager instance = DungeonManager.Instance; if ((Object)(object)instance != (Object)null && instance.NetworklevelOverride && instance.NetworklevelOverrideValue >= 0) { return instance.NetworklevelOverrideValue + 1; } GameManager instance2 = GameManager.Instance; if (!((Object)(object)instance2 == (Object)null)) { return (int)Math.Min(2147483647L, Math.Max(0L, instance2.TotalRoundsPlayed) + 1); } return 1; } } private static FieldInfo Require(Type type, string name) { return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException(type.FullName, name); } private static void Hook(Harmony harmony, Type type, string name, string prefix = null, string postfix = null, string finalizer = null) { MethodInfo methodInfo = type.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMethodException(type.FullName, name); harmony.Patch((MethodBase)methodInfo, Patch(prefix), Patch(postfix), (HarmonyMethod)null, Patch(finalizer), (HarmonyMethod)null); static HarmonyMethod Patch(string method) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown if (method != null) { return new HarmonyMethod(typeof(SpawnDirector).GetMethod(method, BindingFlags.Static | BindingFlags.NonPublic)); } return null; } } internal static void Install() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Harmony val = new Harmony("com.danya.yapyapexpanded.spawndirector.v0120"); try { Type typeFromHandle = typeof(DungeonNpcSpawner); Interval = Require(typeFromHandle, "spawnCheckInterval"); Prefabs = Require(typeFromHandle, "npcs"); Instances = Require(typeFromHandle, "instanceToPrefab"); Counts = Require(typeFromHandle, "npcTypeCounts"); Power = Require(typeFromHandle, "spawnedPowerLevel"); Points = Require(typeFromHandle, "allSpawnPoints"); Distance = Require(typeFromHandle, "minimumDistanceToPlayers"); Despawn = Require(typeFromHandle, "despawnTime"); NextSpawnTimes = typeFromHandle.GetField("nextSpawnTimes", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Type? nestedType = typeFromHandle.GetNestedType("SpawnInfo", BindingFlags.NonPublic); if (nestedType == null) { throw new MissingMemberException("DungeonNpcSpawner.SpawnInfo"); } InfoNpc = Require(nestedType, "npc"); InfoCount = Require(nestedType, "count"); MaxHealth = Require(typeof(NpcHurtbox), "_maxHealth"); Hook(val, typeFromHandle, "Awake", null, "SpawnerAwake"); Hook(val, typeFromHandle, "Initialize", null, "Initialized"); Hook(val, typeof(DungeonManager), "get_CurrentLevelConfig", null, "LevelConfig"); Hook(val, typeFromHandle, "GetCurrentPowerLevel", null, "CurrentPower"); Hook(val, typeFromHandle, "TrySpawn", "BeforeSpawn"); Hook(val, typeFromHandle, "GetPossibleNpcs", null, "ClampGroups"); Hook(val, typeFromHandle, "SelectSpawnPoint", null, "SelectFallbackPoint"); Hook(val, typeFromHandle, "Cleanup", null, "Cleanup"); Hook(val, typeFromHandle, "OnDestroy", "Cleanup"); Hook(val, typeof(NpcBehaviour), "OnStartServer", null, "NpcStarted"); Hook(val, typeof(NetworkBehaviour), "OnStartClient", null, "ClientStarted"); Hook(val, typeFromHandle, "SpawnNpc", null, "Spawned"); ready = true; Plugin.Log.LogInfo((object)"Spawn director ready: Scale Boost quota rules, native spawning, progressive HP retained."); } catch (Exception ex) { ready = false; val.UnpatchSelf(); Plugin.Log.LogError((object)("Spawn director disabled; vanilla spawning retained: " + ex)); } } private static Settings Snapshot(DungeonNpcSpawner spawner) { return SettingsBySpawner.GetValue(spawner, (DungeonNpcSpawner s) => new Settings { Interval = (float)Interval.GetValue(s), Distance = (float)Distance.GetValue(s), Despawn = (float)Despawn.GetValue(s) }); } private static void SpawnerAwake(DungeonNpcSpawner __instance) { if (ready) { Snapshot(__instance); Distance.SetValue(__instance, 10f); Despawn.SetValue(__instance, 300f); } } private static void Configure(DungeonNpcSpawner spawner) { Settings settings = Snapshot(spawner); int quotas = ScaleBoostScore.Quotas; Interval.SetValue(spawner, ScaleBoostRules.Interval(quotas)); Distance.SetValue(spawner, 10f); Despawn.SetValue(spawner, 300f); NpcBehaviour[] array = (NpcBehaviour[])Prefabs.GetValue(spawner); if (array == null) { return; } int num = 0; NpcBehaviour[] array2 = array; foreach (NpcBehaviour val in array2) { if ((Object)(object)val != (Object)null) { if (!settings.OriginalLimits.ContainsKey(val)) { settings.OriginalLimits.Add(val, val.maxSpawnedAmount); } int num2 = settings.OriginalLimits[val]; if (num2 > 0 && !ScaleBoostRules.IsJester(((Object)val).name)) { num += num2; } } } foreach (KeyValuePair originalLimit in settings.OriginalLimits) { if ((Object)(object)originalLimit.Key != (Object)null) { originalLimit.Key.maxSpawnedAmount = ScaleBoostRules.TypeLimit(originalLimit.Value, ScaleBoostRules.IsJester(((Object)originalLimit.Key).name), num, quotas); } } if (settings.Quota != quotas) { settings.Quota = quotas; Plugin.Log.LogInfo((object)("SCALE BOOST quota=" + quotas + " | target active=" + ScaleBoostRules.ActiveLimit(quotas) + " | interval=" + ScaleBoostRules.Interval(quotas) + "s | power floor=" + ScaleBoostRules.PowerFloor(quotas) + " | HP=" + SpawnBalance.HealthMultiplier(Level).ToString("0.###") + "x")); } } private static void Initialized(DungeonNpcSpawner __instance) { if (ready && NetworkServer.active) { Configure(__instance); } } private static void LevelConfig(ref LevelConfig __result) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (ready && NetworkServer.active && __result != null) { LevelConfig val = __result; __result = new LevelConfig { dungeonSet = val.dungeonSet, maxActiveNpcs = Math.Max(val.maxActiveNpcs, ScaleBoostRules.ActiveLimit(ScaleBoostScore.Quotas)), minPowerLevel = val.minPowerLevel, maxPowerLevel = val.maxPowerLevel, maxNpcTier = Math.Max(val.maxNpcTier, 10) }; } } private static void CurrentPower(ref int __result) { if (ready && NetworkServer.active) { __result = Math.Max(__result, ScaleBoostRules.PowerFloor(ScaleBoostScore.Quotas)); } } private static bool BeforeSpawn(DungeonNpcSpawner __instance, ref bool __result) { if (!ready || !NetworkServer.active) { return true; } GameManager instance = GameManager.Instance; if ((Object)(object)instance == (Object)null || !instance.RoundActive || (Object)(object)DungeonManager.Instance == (Object)null || DungeonManager.Instance.CurrentLevelConfig == null) { __result = false; return false; } Configure(__instance); Recount(__instance); if (NextSpawnTimes?.GetValue(__instance) is IDictionary dictionary) { foreach (object item in new ArrayList(dictionary.Keys)) { dictionary[item] = 0f; } } return true; } private static void Recount(DungeonNpcSpawner spawner) { Dictionary dictionary = (Dictionary)Instances.GetValue(spawner); Dictionary dictionary2 = (Dictionary)Counts.GetValue(spawner); List list = new List(); dictionary2.Clear(); int num = 0; foreach (KeyValuePair item in dictionary) { if ((Object)(object)item.Key == (Object)null || item.Key.IsKilled || (Object)(object)item.Value == (Object)null) { list.Add(item.Key); continue; } dictionary2.TryGetValue(item.Value, out var value); dictionary2[item.Value] = value + 1; num += Math.Max(0, item.Value.powerLevel); } foreach (NpcBehaviour item2 in list) { dictionary.Remove(item2); } Power.SetValue(spawner, num); } private static void ClampGroups(DungeonNpcSpawner __instance, object __result) { if (!ready || !NetworkServer.active || (Object)(object)DungeonManager.Instance == (Object)null) { return; } LevelConfig currentLevelConfig = DungeonManager.Instance.CurrentLevelConfig; if (currentLevelConfig == null || !(__result is IList list)) { return; } int count = ((Dictionary)Instances.GetValue(__instance)).Count; for (int num = list.Count - 1; num >= 0; num--) { int num2 = SpawnBalance.GroupCount((int)InfoCount.GetValue(list[num]), count, currentLevelConfig.maxActiveNpcs); if (num2 == 0) { list.RemoveAt(num); } else { InfoCount.SetValue(list[num], num2); } } } private static void SelectFallbackPoint(DungeonNpcSpawner __instance, ref RoomPoint __result) { if (!ready || !NetworkServer.active || (Object)(object)__result != (Object)null) { return; } List list = (List)Points.GetValue(__instance); if (list == null) { return; } int num = 0; foreach (RoomPoint item in list) { if ((Object)(object)item != (Object)null && Random.Range(0, ++num) == 0) { __result = item; } } } private static void ClientStarted(NetworkBehaviour __instance) { NpcBehaviour val = (NpcBehaviour)(object)((__instance is NpcBehaviour) ? __instance : null); if (val != null) { NpcStarted(val); } } private static void Spawned(DungeonNpcSpawner __instance) { if (!ready || !NetworkServer.active) { return; } foreach (KeyValuePair item in (Dictionary)Instances.GetValue(__instance)) { if ((Object)(object)item.Key != (Object)null && !item.Key.IsKilled) { ApplyHealth(item.Key); } } } private static void NpcStarted(NpcBehaviour __instance) { if (!ready || (Object)(object)__instance == (Object)null || __instance.IsKilled) { return; } GameManager instance = GameManager.Instance; DungeonNpcSpawner instance2 = DungeonNpcSpawner.Instance; if ((Object)(object)instance == (Object)null || !instance.RoundActive || (Object)(object)instance2 == (Object)null) { return; } string text = ((Object)__instance).name.Replace("(Clone)", "").Trim(); bool flag = false; NpcBehaviour[] array = (NpcBehaviour[])Prefabs.GetValue(instance2); foreach (NpcBehaviour val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name == text) { flag = true; break; } } if (flag) { ApplyHealth(__instance); } } private static void ApplyHealth(NpcBehaviour npc) { NpcHurtbox component = ((Component)npc).GetComponent(); if (!((Object)(object)component == (Object)null)) { HealthState value = HealthStates.GetValue(component, (NpcHurtbox h) => new HealthState { Baseline = (int)MaxHealth.GetValue(h), Level = Level }); int num = SpawnBalance.ScaleHealth(value.Baseline, value.Level); MaxHealth.SetValue(component, num); if (NetworkServer.active && !value.ServerApplied) { component.Network_health = Math.Max(0, num - Math.Max(0, value.Baseline - component.Health)); value.ServerApplied = true; Plugin.Log.LogInfo((object)("NPC HP " + ((Object)npc).name + " | level=" + value.Level + " | base=" + value.Baseline + " | max=" + num)); } } } private static void Cleanup(DungeonNpcSpawner __instance) { if (!SettingsBySpawner.TryGetValue(__instance, out var value)) { return; } Interval.SetValue(__instance, value.Interval); Distance.SetValue(__instance, value.Distance); Despawn.SetValue(__instance, value.Despawn); foreach (KeyValuePair originalLimit in value.OriginalLimits) { if ((Object)(object)originalLimit.Key != (Object)null) { originalLimit.Key.maxSpawnedAmount = originalLimit.Value; } } value.Quota = -1; } } internal sealed class SpellBook : MonoBehaviour { internal bool Visible; private int page; private readonly MenuNavigation navigation = new MenuNavigation(); private GUIStyle title; private GUIStyle heading; private GUIStyle body; private GUIStyle phrase; private GUIStyle small; internal void Toggle() { if (Visible) { Close(); } else if (ModMenuInput.Open(this)) { Visible = true; navigation.Selected = 0; } } private void Close() { Visible = false; ModMenuInput.Close(this); } private void OnDisable() { Close(); } private void Update() { if (!Visible) { return; } if (ModMenuInput.Owner != this) { Close(); return; } if (!NetworkClient.active || (Object)(object)Pawn.LocalInstance == (Object)null || Pawn.LocalInstance.IsDead || Pawn.LocalInstance.IsExtracted) { Close(); return; } if (ModMenuInput.Back) { Close(); return; } navigation.Update(3); if (ModMenuInput.Submit) { Activate(navigation.Selected); } } private void Activate(int index) { if (navigation.TakeActivation()) { switch (index) { case 0: page = (page + 1) % 2; break; case 1: ModLocalization.Cycle(); break; case 2: Close(); break; } } } private void OnGUI() { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) if (Visible) { if (title == null) { title = new GUIStyle(GUI.skin.label) { fontSize = 22, fontStyle = (FontStyle)1 }; heading = new GUIStyle(GUI.skin.label) { fontSize = 17, fontStyle = (FontStyle)1, wordWrap = true }; body = new GUIStyle(GUI.skin.label) { fontSize = 14, wordWrap = true }; phrase = new GUIStyle(GUI.skin.label) { fontSize = 16, fontStyle = (FontStyle)1 }; small = new GUIStyle(GUI.skin.label) { fontSize = 12, wordWrap = true }; } Matrix4x4 matrix = GUI.matrix; Color color = GUI.color; float num = Mathf.Min(1f, Mathf.Min((float)Screen.width / 1040f, (float)Screen.height / 790f)); GUI.matrix = Matrix4x4.TRS(new Vector3(((float)Screen.width - 1020f * num) / 2f, ((float)Screen.height - 760f * num) / 2f, 0f), Quaternion.identity, Vector3.one * num); GUI.color = Color.white; GUI.Box(new Rect(0f, 0f, 1020f, 760f), GUIContent.none); GUI.Label(new Rect(24f, 14f, 950f, 30f), Loc.Text("book.title"), title); if (navigation.Button(new Rect(24f, 53f, 305f, 32f), 0, Loc.Text((new string[2] { "book.custom", "book.extras" })[page]) + " >")) { Activate(0); } if (navigation.Button(new Rect(346f, 53f, 390f, 32f), 1, Loc.Format("ui.language", ModLocalization.ChoiceLabel))) { Activate(1); } if (navigation.Button(new Rect(753f, 53f, 242f, 32f), 2, Loc.Text("ui.close"))) { Activate(2); } GUI.Label(new Rect(24f, 95f, 970f, 43f), Loc.Text("book.intro"), body); if (page == 0) { DrawSchool(24f, WandKind.Frost, SpellCatalog.Frost); DrawSchool(526f, WandKind.Chaos, SpellCatalog.Chaos); } else { DrawExtras(); } GUI.Label(new Rect(24f, 708f, 972f, 42f), ModMenuInput.Controls, small); GUI.matrix = matrix; GUI.color = color; } } private void DrawSchool(float x, WandKind kind, SpellDefinition[] spells) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) GUI.Label(new Rect(x, 143f, 470f, 26f), InventoryAppearance.GetDisplayName(kind), heading); GUI.Label(new Rect(x, 174f, 470f, 48f), Loc.Text((kind == WandKind.Frost) ? "wand.frost.description" : "wand.chaos.description"), small); for (int i = 0; i < spells.Length; i++) { SpellDefinition spellDefinition = spells[i]; float num = 227 + i * 116; GUI.Label(new Rect(x, num, 470f, 24f), i + 1 + ". " + spellDefinition.LocalName, heading); string text = VoiceVocabularyPatcher.Phrase(spellDefinition.Key); GUI.Label(new Rect(x, num + 24f, 470f, 24f), (text == "—") ? Loc.Text("book.phrase_wait") : text, phrase); GUI.Label(new Rect(x, num + 49f, 470f, 44f), spellDefinition.LocalDescription, body); GUI.Label(new Rect(x, num + 94f, 470f, 20f), Loc.Format("book.charges", spellDefinition.Charges, spellDefinition.Regen), small); } } private void DrawExtras() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < ExtraCatalog.All.Length; i++) { ExtraDefinition extraDefinition = ExtraCatalog.All[i]; float num = 24 + i % 2 * 502; float num2 = 153 + i / 2 * 175; GUI.color = ExtraVisual.Tint(extraDefinition.Id); GUI.Label(new Rect(num, num2, 470f, 47f), Loc.Text("school." + extraDefinition.School.ToLowerInvariant()) + " — " + Loc.Text(extraDefinition.Ru), heading); GUI.Label(new Rect(num, num2 + 49f, 470f, 24f), VoiceVocabularyPatcher.Phrase(extraDefinition.Key), phrase); GUI.color = Color.white; GUI.Label(new Rect(num, num2 + 76f, 470f, 55f), Loc.Text(extraDefinition.Description), body); GUI.Label(new Rect(num, num2 + 133f, 470f, 34f), Loc.Format("book.duration", extraDefinition.Charges, extraDefinition.Regen, extraDefinition.Duration), small); } } } internal enum SpellId { FrostBind, FrostShard, FrostNova, FrostBlizzard, ChaosRoll, ChaosBolt, ChaosVortex, ChaosBurst } internal sealed class SpellDefinition { internal readonly SpellId Id; internal readonly WandKind Kind; internal readonly string Key; internal readonly string NameRu; internal readonly string NameEn; internal readonly string DescriptionRu; internal readonly string RootRu; internal readonly string RootEn; internal readonly string EndingRu; internal readonly string EndingEn; internal readonly int Charges; internal readonly float Cooldown; internal readonly float Regen; internal readonly float Range; internal readonly float Radius; internal readonly float Duration; internal readonly int Damage; internal readonly int FrozenBonus; internal readonly int DamageVariance; internal string LocalName => Loc.Text("spell." + Id.ToString().ToLowerInvariant() + ".name"); internal string LocalDescription => Loc.Text("spell." + Id.ToString().ToLowerInvariant() + ".description"); internal SpellDefinition(SpellId id, WandKind kind, string nameRu, string nameEn, string endingRu, string endingEn, string descriptionRu, int charges, float cooldown, float regen, float range, float radius = 0f, float duration = 0f, int damage = 0, int frozenBonus = 0, int damageVariance = 0) { Id = id; Kind = kind; Key = "YAPYAPEXP_" + id.ToString().ToUpperInvariant(); NameRu = Loc.For("ru", nameRu); NameEn = Loc.For("en", nameEn); DescriptionRu = Loc.For("ru", descriptionRu); RootRu = ((kind == WandKind.Frost) ? "НИВА" : "АЛЕА"); RootEn = ((kind == WandKind.Frost) ? "NIVA" : "ALEA"); EndingRu = endingRu; EndingEn = endingEn; Charges = charges; Cooldown = cooldown; Regen = regen; Range = range; Radius = radius; Duration = duration; Damage = damage; FrozenBonus = frozenBonus; DamageVariance = damageVariance; } } internal static class SpellCatalog { internal const string Prefix = "YAPYAPEXP_"; internal const int SpellsPerWand = 4; internal static readonly SpellDefinition[] Frost = new SpellDefinition[4] { new SpellDefinition(SpellId.FrostBind, WandKind.Frost, "spell.frostbind.name", "spell.frostbind.name", "СТАЗИС", "STASIS", "spell.frostbind.description", 3, 0f, 11f, 12f, 0f, 3f), new SpellDefinition(SpellId.FrostShard, WandKind.Frost, "spell.frostshard.name", "spell.frostshard.name", "ПИКА", "LANCE", "spell.frostshard.description", 3, 0f, 8f, 16f, 0f, 0f, 16, 16), new SpellDefinition(SpellId.FrostNova, WandKind.Frost, "spell.frostnova.name", "spell.frostnova.name", "НОВА", "NOVA", "spell.frostnova.description", 2, 0f, 18f, 0f, 3.5f, 1.5f, 8), new SpellDefinition(SpellId.FrostBlizzard, WandKind.Frost, "spell.frostblizzard.name", "spell.frostblizzard.name", "БОРЕЙ", "BOREAL", "spell.frostblizzard.description", 1, 0f, 28f, 14f, 3f, 4.5f) }; internal static readonly SpellDefinition[] Chaos = new SpellDefinition[4] { new SpellDefinition(SpellId.ChaosRoll, WandKind.Chaos, "spell.chaosroll.name", "spell.chaosroll.name", "ФОРТИС", "FORTIS", "spell.chaosroll.description", 3, 0f, 14f, 12f, 6f), new SpellDefinition(SpellId.ChaosBolt, WandKind.Chaos, "spell.chaosbolt.name", "spell.chaosbolt.name", "ИСКРА", "SPARK", "spell.chaosbolt.description", 3, 0f, 10f, 16f, 0f, 0.5f, 12, 0, 12), new SpellDefinition(SpellId.ChaosVortex, WandKind.Chaos, "spell.chaosvortex.name", "spell.chaosvortex.name", "ВОРТЕКС", "VORTEX", "spell.chaosvortex.description", 2, 0f, 20f, 14f, 3.5f, 3f), new SpellDefinition(SpellId.ChaosBurst, WandKind.Chaos, "spell.chaosburst.name", "spell.chaosburst.name", "БЛАСТ", "BURST", "spell.chaosburst.description", 2, 0f, 20f, 0f, 5f, 1f, 10) }; internal static SpellDefinition[] For(WandKind kind) { if (kind != WandKind.Frost) { return Chaos; } return Frost; } internal static SpellDefinition Find(string key) { if (string.IsNullOrEmpty(key) || !key.StartsWith("YAPYAPEXP_", StringComparison.Ordinal)) { return null; } SpellDefinition[] frost = Frost; foreach (SpellDefinition spellDefinition in frost) { if (spellDefinition.Key == key) { return spellDefinition; } } frost = Chaos; foreach (SpellDefinition spellDefinition2 in frost) { if (spellDefinition2.Key == key) { return spellDefinition2; } } return null; } internal static int Roll(Random random) { return random.Next(1, 7); } internal static string RollName(int face, bool russian) { if (face < 1 || face > 6) { return ""; } return Loc.For(russian ? "ru" : "en", "die." + face); } } internal static class SpellTargets { internal static void Aim(Spell spell, out Vector3 origin, out Vector3 direction) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) origin = ((Component)spell).transform.position; direction = ((Component)spell).transform.forward; NetworkIdentity casterIdentity = spell.CasterIdentity; if ((Object)(object)casterIdentity == (Object)null) { return; } Pawn component = ((Component)casterIdentity).GetComponent(); Vector3 val; if ((Object)(object)component != (Object)null) { origin = component.LookOrigin; if ((Object)(object)component.Blackboard != (Object)null) { Vector3 aimDirection = component.Blackboard.AimDirection; if (((Vector3)(ref aimDirection)).sqrMagnitude > 0.001f) { aimDirection = component.Blackboard.AimDirection; val = ((Vector3)(ref aimDirection)).normalized; goto IL_0098; } } val = ((Component)casterIdentity).transform.forward; goto IL_0098; } origin = ((Component)casterIdentity).transform.position; direction = ((Component)casterIdentity).transform.forward; return; IL_0098: direction = val; } private static bool OwnCollider(Spell spell, Collider collider) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)collider == (Object)null) { return true; } NetworkIdentity componentInParent = ((Component)collider).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && ((Object)(object)componentInParent == (Object)(object)spell.CasterIdentity || (Object)(object)componentInParent == (Object)(object)((NetworkBehaviour)spell).netIdentity)) { return true; } NetworkPuppetProp componentInParent2 = ((Component)collider).GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null && (int)componentInParent2.CurrentState.state != 0 && (Object)(object)spell.CasterIdentity != (Object)null) { return componentInParent2.CurrentState.interactorNetId == spell.CasterIdentity.netId; } return false; } internal static bool FirstHit(Spell spell, float range, out RaycastHit first) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Aim(spell, out var origin, out var direction); RaycastHit[] array = Physics.RaycastAll(origin, direction, range, -1, (QueryTriggerInteraction)1); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val = array2[num]; if (!OwnCollider(spell, ((RaycastHit)(ref val)).collider)) { first = val; return true; } } first = default(RaycastHit); return false; } internal static GameObject Resolve(Collider collider) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)collider == (Object)null || !((Component)collider).gameObject.activeInHierarchy) { return null; } if ((Object)(object)((Component)collider).GetComponentInParent() != (Object)null) { return null; } NpcBehaviour componentInParent = ((Component)collider).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { if (!componentInParent.IsKilled) { return ((Component)componentInParent).gameObject; } return null; } Rigidbody attachedRigidbody = collider.attachedRigidbody; if ((Object)(object)attachedRigidbody == (Object)null || attachedRigidbody.isKinematic) { return null; } NetworkPuppetProp componentInParent2 = ((Component)attachedRigidbody).GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null) { if (componentInParent2.IsShopItem || (int)componentInParent2.CurrentState.state != 0 || componentInParent2 is NetworkPuppetWandProp) { return null; } return ((Component)componentInParent2).gameObject; } return ((Component)attachedRigidbody).gameObject; } internal static List Nearby(Spell spell, Vector3 center, float radius) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) List list = new List(); HashSet hashSet = new HashSet(); Collider[] array = Physics.OverlapSphere(center, radius, -1, (QueryTriggerInteraction)1); foreach (Collider val in array) { if (OwnCollider(spell, val)) { continue; } GameObject val2 = Resolve(val); if (!((Object)(object)val2 == (Object)null) && !hashSet.Contains(val2)) { Vector3 val3 = val.ClosestPoint(center); Vector3 val4 = val3 - center; if (!(((Vector3)(ref val4)).sqrMagnitude > radius * radius) && Visible(spell, center, val3, val2)) { hashSet.Add(val2); list.Add(val2); } } } return list; } private static bool Visible(Spell spell, Vector3 origin, Vector3 point, GameObject target) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) Vector3 val = point - origin; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { return true; } RaycastHit[] array = Physics.RaycastAll(origin, ((Vector3)(ref val)).normalized, ((Vector3)(ref val)).magnitude + 0.025f, -1, (QueryTriggerInteraction)1); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val2 = array2[num]; if (!OwnCollider(spell, ((RaycastHit)(ref val2)).collider)) { return (Object)(object)Resolve(((RaycastHit)(ref val2)).collider) == (Object)(object)target; } } return true; } internal static void Damage(GameObject root, NetworkIdentity caster, int amount, Vector3 direction) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active && !((Object)(object)root == (Object)null) && amount > 0) { NpcBehaviour component = root.GetComponent(); if ((Object)(object)component != (Object)null && !component.IsKilled) { component.OnHit(amount, direction, false, caster); } } } internal static void DamageProp(GameObject root, NetworkIdentity caster, int amount, Vector3 direction) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || (Object)(object)root == (Object)null || (Object)(object)caster == (Object)null || amount <= 0 || (Object)(object)root.GetComponentInParent() != (Object)null || (Object)(object)root.GetComponent() != (Object)null) { return; } NetworkPuppetProp component = root.GetComponent(); if ((Object)(object)component != (Object)null && (component.IsShopItem || (int)component.CurrentState.state != 0 || component is NetworkPuppetWandProp)) { return; } NetworkPhysicsPropDestroy val = root.GetComponent(); if ((Object)(object)val == (Object)null) { val = root.GetComponentInChildren(); } if (!((Object)(object)val == (Object)null) && !val.invincible) { ValuableObject component2 = ((Component)val).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.SetAndPropagateRecentInteractor(caster.netId); } val.ApplyDamage(amount, direction * 5f, caster); } } internal static void Impulse(GameObject root, Vector3 velocity) { //IL_0046: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || (Object)(object)root == (Object)null || (Object)(object)root.GetComponent() != (Object)null || (Object)(object)root.GetComponentInParent() != (Object)null) { return; } NetworkPuppetProp component = root.GetComponent(); if ((Object)(object)component != (Object)null && (component.IsShopItem || (int)component.CurrentState.state != 0 || component is NetworkPuppetWandProp)) { return; } Rigidbody[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Rigidbody val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !val.isKinematic && (int)val.constraints != 126) { val.AddForce(velocity, (ForceMode)2); val.linearVelocity = Vector3.ClampMagnitude(val.linearVelocity, 18f); } } } } internal sealed class SpellZone : MonoBehaviour { private static readonly List Active = new List(); private Spell _spell; private SpellDefinition _definition; private double _expires; private double _nextTick; internal static void Create(Spell spell, SpellDefinition definition, Vector3 center) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) for (int num = Active.Count - 1; num >= 0; num--) { SpellZone spellZone = Active[num]; if ((Object)(object)spellZone == (Object)null) { Active.RemoveAt(num); } else if ((Object)(object)spellZone._spell == (Object)(object)spell) { spellZone.End(); } } if (Active.Count >= 16) { Active[0].End(); } GameObject val = new GameObject("YAPYAPExpanded_" + definition.Id.ToString() + "_Zone"); val.transform.position = center; SpellZone spellZone2 = val.AddComponent(); spellZone2._spell = spell; spellZone2._definition = definition; spellZone2._expires = NetworkTime.time + (double)definition.Duration; Active.Add(spellZone2); } private void Update() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || (Object)(object)_spell == (Object)null || (Object)(object)_spell.CasterIdentity == (Object)null || NetworkTime.time >= _expires) { End(); } else { if (NetworkTime.time < _nextTick) { return; } _nextTick = NetworkTime.time + 0.2; foreach (GameObject item in SpellTargets.Nearby(_spell, ((Component)this).transform.position, _definition.Radius)) { if (_definition.Id == SpellId.FrostBlizzard) { FreezeState.ApplyTo(item, (float)Math.Min(0.35, _expires - NetworkTime.time), frost: true); continue; } Vector3 val = ((Component)this).transform.position - item.transform.position; Vector3 val2 = Vector3.Cross(Vector3.up, ((Vector3)(ref val)).normalized); SpellTargets.Impulse(item, (((Vector3)(ref val)).normalized * 8f + val2 * 6f + Vector3.up * 2f) * 0.2f); } } } private void End() { Active.Remove(this); ((Behaviour)this).enabled = false; Object.Destroy((Object)(object)((Component)this).gameObject); } private void OnDestroy() { Active.Remove(this); } } internal static class SpellVanilla { internal static void Install(Harmony harmony) { Copy(harmony, "Initialize", "Initialize", typeof(NetworkIdentity)); Copy(harmony, "CanCast", "CanCast"); Copy(harmony, "OnSpellActivate", "Activate"); Copy(harmony, "OnSpellDeactivate", "Deactivate"); Copy(harmony, "SetCastData", "SetCastData"); Copy(harmony, "SetWandHeld", "SetWandHeld", typeof(bool)); Copy(harmony, "UserCode_RpcPlayEffect__SpellEffectType__Vector3__Quaternion", "ClientEffect", typeof(SpellEffectType), typeof(Vector3), typeof(Quaternion)); Copy(harmony, "Update", "Update"); Copy(harmony, "OnCasterIdentityChanged", "CasterChanged", typeof(NetworkIdentity), typeof(NetworkIdentity)); Copy(harmony, "OnCurrentChargesChanged", "ChargesChanged", typeof(int), typeof(int)); Copy(harmony, "OnIsCastingChanged", "CastingChanged", typeof(bool), typeof(bool)); } private static void Copy(Harmony harmony, string name, string standin, params Type[] parameters) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown MethodInfo method = typeof(Spell).GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null); if (method == null) { throw new MissingMethodException(typeof(Spell).FullName, name); } MethodInfo method2 = typeof(SpellVanilla).GetMethod(standin, BindingFlags.Static | BindingFlags.NonPublic); harmony.CreateReversePatcher((MethodBase)method, new HarmonyMethod(method2)).Patch((HarmonyReversePatchType)0); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void Initialize(Spell spell, NetworkIdentity caster) { throw new NotSupportedException("Initialize reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static bool CanCast(Spell spell) { throw new NotSupportedException("CanCast reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void Activate(Spell spell) { throw new NotSupportedException("Activate reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void Deactivate(Spell spell) { throw new NotSupportedException("Deactivate reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void SetCastData(Spell spell) { throw new NotSupportedException("SetCastData reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void SetWandHeld(Spell spell, bool held) { throw new NotSupportedException("SetWandHeld reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void ClientEffect(Spell spell, SpellEffectType effect, Vector3 position, Quaternion rotation) { throw new NotSupportedException("ClientEffect reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void Update(Spell spell) { throw new NotSupportedException("Update reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void CasterChanged(Spell spell, NetworkIdentity oldCaster, NetworkIdentity newCaster) { throw new NotSupportedException("CasterChanged reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void ChargesChanged(Spell spell, int oldValue, int newValue) { throw new NotSupportedException("ChargesChanged reverse patch missing"); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void CastingChanged(Spell spell, bool oldValue, bool newValue) { throw new NotSupportedException("CastingChanged reverse patch missing"); } } internal static class SpellVisuals { internal static void Play(Spell spell, SpellDefinition definition, SpellEffectType effect, Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 //IL_003a: 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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if ((int)effect == 0 || (int)effect == 3 || (int)effect == 1) { Color color = ((definition.Kind == WandKind.Frost) ? new Color(0.35f, 0.85f, 1f) : new Color(0.85f, 0.3f, 1f)); bool flag = (int)effect == 3 && (definition.Id == SpellId.FrostBind || definition.Id == SpellId.FrostShard || definition.Id == SpellId.ChaosBolt); bool flag2 = (int)effect == 1; GameObject val = new GameObject("YAPYAPExpanded_SpellVFX"); val.transform.position = point; SpellRing spellRing = val.AddComponent(); SpellTargets.Aim(spell, out var origin, out var _); NetworkPuppetWandProp componentInParent = ((Component)spell).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.WandTip != (Object)null) { origin = componentInParent.WandTip.position; } float radius = (((int)effect == 0) ? 0.25f : ((definition.Radius > 0f) ? definition.Radius : 0.7f)); spellRing.Initialize(color, radius, flag2 ? definition.Duration : (flag ? 0.35f : 0.65f), flag2, flag, origin); } } } internal sealed class SpellRing : MonoBehaviour { private LineRenderer _line; private Material _material; private Color _color; private float _start; private float _duration; private float _radius; private bool _zone; private bool _beam; private Vector3 _origin; internal void Initialize(Color color, float radius, float duration, bool zone, bool beam, Vector3 origin) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Color"); if ((Object)(object)val == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } _material = new Material(val); _material.color = color; _line = ((Component)this).gameObject.AddComponent(); ((Renderer)_line).sharedMaterial = _material; _line.useWorldSpace = true; _line.loop = !beam; _line.positionCount = (beam ? 2 : 49); _line.widthMultiplier = (beam ? 0.065f : 0.04f); LineRenderer line = _line; Color startColor = (_line.endColor = color); line.startColor = startColor; _color = color; _radius = radius; _duration = duration; _start = Time.time; _zone = zone; _beam = beam; _origin = origin; Update(); } private void Update() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_line == (Object)null) { return; } float num = Time.time - _start; if (num >= _duration) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } float a = (_zone ? Mathf.Min(1f, (_duration - num) * 2f) : (1f - num / _duration)); Color color = _color; color.a = a; LineRenderer line = _line; Color startColor = (_line.endColor = color); line.startColor = startColor; if (_beam) { _line.SetPosition(0, _origin); _line.SetPosition(1, ((Component)this).transform.position); return; } float num2 = _radius * (_zone ? 1f : Mathf.Lerp(0.15f, 1f, num / _duration)); for (int i = 0; i < 49; i++) { float num3 = (float)i * MathF.PI * 2f / 48f + (_zone ? num : 0f); float num4 = (_zone ? (Mathf.Sin(num3 * 4f + num * 3f) * 0.1f) : 0f); _line.SetPosition(i, ((Component)this).transform.position + new Vector3(Mathf.Cos(num3) * num2, num4 + 0.08f, Mathf.Sin(num3) * num2)); } } private void OnDestroy() { if ((Object)(object)_material != (Object)null) { Object.Destroy((Object)(object)_material); } } } internal static class UpgradeInventory { internal static readonly string[] CapacityMethods = new string[12] { "OnStartServer", "OnStartClient", "ServerSerializeToKvp", "ServerTryRestoreFromKvp", "IsFull", "ServerTryAddItem", "ServerAddItemToSlot", "ServerRemoveFromSlot", "SelectSlotWithMainHand", "UserCode_CmdMoveItemInInventory__UInt32__Int32", "UserCode_CmdSwapSlotWithRightHand__Int32", "UserCode_CmdCycleSlot__Boolean" }; private static readonly FieldInfo Slots = typeof(UIInventory).GetField("inventorySlots", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo PlayerInventory = typeof(UIInventory).GetField("_playerInventory", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly PropertyInfo MovementBody = typeof(BaseControllerComponent).GetProperty("Rigidbody", BindingFlags.Instance | BindingFlags.NonPublic); internal static void Install(Harmony harmony) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown string[] capacityMethods = CapacityMethods; foreach (string text in capacityMethods) { MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), text, (Type[])null, (Type[])null) ?? throw new MissingMethodException(text); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(UpgradeInventory), "ExpandCapacity", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } harmony.Patch((MethodBase)AccessTools.Method(typeof(PawnInventory), "ServerTryRestoreFromKvp", (Type[])null, (Type[])null), new HarmonyMethod(typeof(UpgradeInventory), "BeforeRestore", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(UIInventory), "RefreshInventoryDisplay", (Type[])null, (Type[])null), new HarmonyMethod(typeof(UpgradeInventory), "RefreshSlots", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(UIInventory), "IsMouseOverUI", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(UpgradeInventory), "ExtraSlotHover", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(ControllerMovementComponent), "FixedUpdateComponent", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(UpgradeInventory), "MovementSpeed", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } internal static int Capacity(PawnInventory inventory) { if ((Object)(object)inventory == (Object)null) { return 3; } int num = UpgradeRules.Capacity(CharacterUpgrades.Levels(((Component)inventory).GetComponent()).Inventory); if (!NetworkServer.active) { return Math.Max(num, inventory.Items.Count); } return num; } internal static int LastSlot(PawnInventory inventory) { return Capacity(inventory) - 1; } private static void BeforeRestore(PawnInventory __instance) { CharacterUpgrades.EnsureSlots(((Component)__instance).GetComponent()); } internal static IEnumerable ExpandCapacity(IEnumerable instructions, MethodBase __originalMethod) { bool lastIndex = __originalMethod.Name == "ServerSerializeToKvp" || __originalMethod.Name == "ServerTryRestoreFromKvp" || __originalMethod.Name == "UserCode_CmdCycleSlot__Boolean"; int replacements = 0; List code = instructions.ToList(); for (int index = 0; index < code.Count; index++) { CodeInstruction val = code[index]; bool flag = index + 1 < code.Count && code[index + 1].operand is MethodInfo methodInfo && ((methodInfo.DeclaringType == typeof(Mathf) && methodInfo.Name == "Clamp") || methodInfo.Name == "set_NetworkCurrentMainHandSlot"); bool capacity = CodeInstructionExtensions.LoadsConstant(val, 3L); bool flag2 = lastIndex && flag && CodeInstructionExtensions.LoadsConstant(val, 2L); if (capacity || flag2) { CodeInstruction val2 = new CodeInstruction(val); val2.opcode = OpCodes.Ldarg_0; val2.operand = null; yield return val2; yield return new CodeInstruction(OpCodes.Call, (object)typeof(UpgradeInventory).GetMethod(capacity ? "Capacity" : "LastSlot", BindingFlags.Static | BindingFlags.NonPublic)); replacements++; } else { yield return val; } } if (replacements == 0) { throw new InvalidOperationException("Inventory capacity IL changed: " + __originalMethod.Name); } } internal static IEnumerable MovementSpeed(IEnumerable instructions) { bool found = false; bool additive = false; foreach (CodeInstruction input in instructions) { yield return input; if (additive && input.opcode == OpCodes.Add) { yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null); yield return new CodeInstruction(OpCodes.Call, (object)typeof(UpgradeInventory).GetMethod("ScaleSpeed", BindingFlags.Static | BindingFlags.NonPublic)); found = true; } additive = input.operand is MethodInfo methodInfo && methodInfo.Name == "get_AdditiveWalkSpeed"; } if (!found) { throw new InvalidOperationException("Player speed IL changed"); } } internal static float ScaleSpeed(float value, ControllerMovementComponent movement) { object? value2 = MovementBody.GetValue(movement); Rigidbody val = (Rigidbody)((value2 is Rigidbody) ? value2 : null); Pawn pawn = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInParent() : null); return value * UpgradeRules.Speed(CharacterUpgrades.Levels(pawn).Speed); } private static void RefreshSlots(UIInventory __instance) { object? value = PlayerInventory.GetValue(__instance); PawnInventory val = (PawnInventory)((value is PawnInventory) ? value : null); if ((Object)(object)val == (Object)null) { return; } UIInventorySlot[] array = Slots.GetValue(__instance) as UIInventorySlot[]; if (array == null || array.Length == 0) { return; } int num = Math.Max(3, val.Items.Count); UpgradeSlotRow upgradeSlotRow = ((Component)__instance).GetComponent(); if (array.Length < num) { if ((Object)(object)upgradeSlotRow == (Object)null) { upgradeSlotRow = ((Component)__instance).gameObject.AddComponent(); } upgradeSlotRow.EnsureRoot(((Component)array[2]).transform.parent); List list = new List(array); UIInventorySlot val2 = array[2]; while (list.Count < num) { UIInventorySlot val3 = Object.Instantiate(val2, (Transform)(object)upgradeSlotRow.Root); ((Object)val3).name = "YAPYAPExpanded_InventorySlot_" + list.Count; val3.Initialize(list.Count, __instance); val3.ClearSlot(); list.Add(val3); } array = list.ToArray(); Slots.SetValue(__instance, array); } for (int i = 0; i < array.Length; i++) { ((Component)array[i]).gameObject.SetActive(i < num); } if ((Object)(object)upgradeSlotRow != (Object)null) { upgradeSlotRow.Slots = array; upgradeSlotRow.Arrange(); } } private static void ExtraSlotHover(UIInventory __instance, ref bool __result) { UpgradeSlotRow component = ((Component)__instance).GetComponent(); if (!__result && (Object)(object)component != (Object)null) { __result = component.ContainsPointer(); } } } internal sealed class UpgradeSlotRow : MonoBehaviour { internal RectTransform Root; internal UIInventorySlot[] Slots; private readonly Vector3[] corners = (Vector3[])(object)new Vector3[4]; internal void EnsureRoot(Transform parent) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Root != (Object)null)) { Root = new GameObject("YAPYAPExpanded_ExtraSlotRow", new Type[2] { typeof(RectTransform), typeof(LayoutElement) }).GetComponent(); ((Transform)Root).SetParent(parent, false); ((Component)Root).GetComponent().ignoreLayout = true; RectTransform root = Root; RectTransform root2 = Root; RectTransform root3 = Root; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 0.5f); root3.pivot = val; Vector2 anchorMin = (root2.anchorMax = val); root.anchorMin = anchorMin; } } private void LateUpdate() { Arrange(); } internal void Arrange() { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Expected O, but got Unknown //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Root == (Object)null || Slots == null || Slots.Length <= 3) { return; } int num = 0; for (int i = 3; i < Slots.Length; i++) { if (((Component)Slots[i]).gameObject.activeSelf) { num++; } } ((Component)Root).gameObject.SetActive(num > 0); if (num == 0) { return; } Transform parent = ((Transform)Root).parent; float num2 = float.PositiveInfinity; float num3 = float.NegativeInfinity; float num4 = float.NegativeInfinity; float num5 = 0f; float num6 = 0f; for (int j = 0; j < 3; j++) { ((RectTransform)((Component)Slots[j]).transform).GetWorldCorners(corners); float num7 = float.PositiveInfinity; float num8 = float.NegativeInfinity; float num9 = float.PositiveInfinity; float num10 = float.NegativeInfinity; Vector3[] array = corners; foreach (Vector3 val in array) { Vector3 val2 = parent.InverseTransformPoint(val); num7 = Mathf.Min(num7, val2.x); num8 = Mathf.Max(num8, val2.x); num9 = Mathf.Min(num9, val2.y); num10 = Mathf.Max(num10, val2.y); } num2 = Mathf.Min(num2, num7); num3 = Mathf.Max(num3, num8); num4 = Mathf.Max(num4, num10); num5 = Mathf.Max(num5, num8 - num7); num6 = Mathf.Max(num6, num10 - num9); } if (num5 < 1f || num6 < 1f) { return; } float num11 = 8f; Root.sizeDelta = new Vector2((float)num * num5 + (float)(num - 1) * num11, num6); ((Transform)Root).localPosition = new Vector3((num2 + num3) / 2f, num4 + num11 + num6 / 2f, 0f); int num12 = 0; Vector2 val4 = default(Vector2); for (int l = 3; l < Slots.Length; l++) { RectTransform val3 = (RectTransform)((Component)Slots[l]).transform; if (((Component)val3).gameObject.activeSelf) { ((Vector2)(ref val4))..ctor(0.5f, 0.5f); val3.pivot = val4; Vector2 anchorMin = (val3.anchorMax = val4); val3.anchorMin = anchorMin; ((Transform)val3).localScale = Vector3.one; ((Transform)val3).localRotation = Quaternion.identity; val3.sizeDelta = new Vector2(num5, num6); val3.anchoredPosition = new Vector2(SlotOffset(num12++, num, num5, num11), 0f); } } } internal static float SlotOffset(int index, int count, float width, float gap) { return ((float)index - (float)(count - 1) * 0.5f) * (width + gap); } internal bool ContainsPointer() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Root == (Object)null || !((Component)Root).gameObject.activeInHierarchy) { return false; } Canvas componentInParent = ((Component)Root).GetComponentInParent(); Camera val = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null); return RectTransformUtility.RectangleContainsScreenPoint(Root, Vector2.op_Implicit(Input.mousePosition), val); } private void OnDestroy() { if ((Object)(object)Root != (Object)null) { Object.Destroy((Object)(object)((Component)Root).gameObject); } } } internal sealed class UpgradeMenu : MonoBehaviour { private static UpgradeMenu instance; private bool visible; private bool pending; private bool showUpgradeHint; private uint merchant; private uint token; private float sentAt; private string status = ""; private GUIStyle title; private GUIStyle body; private GUIStyle small; private readonly MenuNavigation navigation = new MenuNavigation(); private void Awake() { instance = this; } private static ShopkeeperStateMachine LookAtMerchant() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) Pawn localInstance = Pawn.LocalInstance; if ((Object)(object)localInstance == (Object)null || localInstance.IsDead || localInstance.IsExtracted) { return null; } RaycastHit[] array = Physics.RaycastAll(localInstance.LookOrigin, localInstance.AimDirection, 4f, -1, (QueryTriggerInteraction)1); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val = array2[num]; NetworkIdentity componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)(object)((NetworkBehaviour)localInstance).netIdentity)) { if (!((Object)(object)componentInParent != (Object)null)) { return null; } return ((Component)componentInParent).GetComponentInChildren(true); } } return null; } internal static bool TryOpenNearMerchant() { UpgradeMenu upgradeMenu = instance; if ((Object)(object)upgradeMenu == (Object)null || !CharacterUpgrades.Ready || !NetworkClient.ready) { return false; } if (upgradeMenu.pending) { return true; } if (!ModMenuInput.CanOpen) { return false; } ShopkeeperStateMachine val = LookAtMerchant(); if ((Object)(object)val == (Object)null) { return false; } upgradeMenu.merchant = ((NetworkBehaviour)val).netIdentity.netId; upgradeMenu.Send(-1, 0); return true; } private void Send(int kind, int expected) { pending = true; sentAt = Time.unscaledTime; token++; NetworkClient.Send(new UpgradeRequest { Merchant = merchant, Token = token, Kind = kind, Expected = expected }, 0); } internal static void Receive(UpgradeState state) { UpgradeMenu upgradeMenu = instance; if (!((Object)(object)upgradeMenu == (Object)null) && !((Object)(object)Pawn.LocalInstance == (Object)null) && state.Pawn == ((NetworkBehaviour)Pawn.LocalInstance).netId && state.Token != 0 && state.Token == upgradeMenu.token && upgradeMenu.pending) { upgradeMenu.pending = false; upgradeMenu.status = state.Result ?? ""; if (state.Open && CharacterUpgrades.MerchantValid(Pawn.LocalInstance, upgradeMenu.merchant, out var _)) { upgradeMenu.Open(); } } } private void Open() { if (!visible && ModMenuInput.Open(this)) { visible = true; navigation.Selected = 0; } } private void Close() { visible = false; pending = false; ModMenuInput.Close(this); } private void Activate(int selection) { if (!navigation.TakeActivation()) { return; } switch (selection) { case 3: Close(); return; case 4: ModLocalization.Cycle(); return; } if (!pending && !((Object)(object)Pawn.LocalInstance == (Object)null)) { int num = CharacterUpgrades.Levels(Pawn.LocalInstance).Get(selection); int gold = (((Object)(object)GameManager.Instance != (Object)null) ? GameManager.Instance.Gold : 0); if (UpgradeRules.CanBuy(selection, num, num, gold)) { Send(selection, num); } } } private void Update() { showUpgradeHint = false; if (pending && Time.unscaledTime - sentAt > 4f) { pending = false; status = "error.timeout"; } if (visible) { if (ModMenuInput.Owner != this) { Close(); return; } if (!NetworkClient.active || !CharacterUpgrades.MerchantValid(Pawn.LocalInstance, merchant, out var _)) { Close(); return; } if (ModMenuInput.Back || Input.GetKeyDown((KeyCode)285)) { Close(); return; } navigation.Update(5); if (ModMenuInput.Submit) { Activate(navigation.Selected); } } else if (CharacterUpgrades.Ready && !pending && NetworkClient.active && NetworkClient.ready && ModMenuInput.CanOpen) { showUpgradeHint = (Object)(object)LookAtMerchant() != (Object)null; if (Input.GetKeyDown((KeyCode)285)) { TryOpenNearMerchant(); } } if (ModMenuInput.Busy || !NetworkClient.active) { return; } Pawn localInstance = Pawn.LocalInstance; if ((Object)(object)((localInstance != null) ? localInstance.Inventory : null) != (Object)null && (Object)(object)InputManager.Instance != (Object)null && !InputManager.Instance.IsInputLocked) { if (Input.GetKeyDown((KeyCode)52) && Pawn.LocalInstance.Inventory.Items.Count > 3) { Pawn.LocalInstance.Inventory.CmdSelectSlotWithMainHand(3); } if (Input.GetKeyDown((KeyCode)53) && Pawn.LocalInstance.Inventory.Items.Count > 4) { Pawn.LocalInstance.Inventory.CmdSelectSlotWithMainHand(4); } } } private void OnGUI() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_051d: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Unknown result type (might be due to invalid IL or missing references) if (!visible) { if (showUpgradeHint) { GUI.Box(new Rect((float)((Screen.width - 440) / 2), (float)Screen.height * 0.72f, 440f, 30f), Loc.Format("upgrade.hint", ModMenuInput.OpenLabel)); } } else { if ((Object)(object)Pawn.LocalInstance == (Object)null) { return; } if (title == null) { title = new GUIStyle(GUI.skin.label) { fontSize = 22, fontStyle = (FontStyle)1 }; body = new GUIStyle(GUI.skin.label) { fontSize = 17, wordWrap = true }; small = new GUIStyle(GUI.skin.label) { fontSize = 14, wordWrap = true }; } Matrix4x4 matrix = GUI.matrix; float num = Mathf.Min(1f, Mathf.Min((float)Screen.width / 850f, (float)Screen.height / 650f)); GUI.matrix = Matrix4x4.TRS(new Vector3(((float)Screen.width - 820f * num) / 2f, ((float)Screen.height - 620f * num) / 2f, 0f), Quaternion.identity, Vector3.one * num); GUI.Box(new Rect(0f, 0f, 820f, 620f), GUIContent.none); GUI.Label(new Rect(24f, 18f, 590f, 32f), Loc.Text("upgrade.title"), title); if (navigation.Button(new Rect(645f, 17f, 150f, 32f), 3, Loc.Text("ui.close"))) { Activate(3); } int num2 = (((Object)(object)GameManager.Instance != (Object)null) ? GameManager.Instance.Gold : 0); GUI.Label(new Rect(24f, 59f, 772f, 45f), Loc.Format("upgrade.gold", num2), small); UpgradeLevels upgradeLevels = CharacterUpgrades.Levels(Pawn.LocalInstance); for (int i = 0; i < 3; i++) { int num3 = upgradeLevels.Get(i); int num4 = UpgradeRules.Max(i); int num5 = UpgradeRules.Price(i, num3); float num6 = 112 + i * 119; GUI.Box(new Rect(20f, num6, 780f, 108f), GUIContent.none); GUI.Label(new Rect(35f, num6 + 8f, 505f, 27f), Loc.Text((new string[3] { "upgrade.health", "upgrade.speed", "upgrade.inventory" })[i]) + " " + num3 + " / " + num4, body); string text = i switch { 1 => Loc.Format("upgrade.speed_effect", 5f), 0 => Loc.Format("upgrade.hp_effect", 10), _ => Loc.Format("upgrade.slots_effect", 1), }; GUI.Label(new Rect(35f, num6 + 42f, 490f, 46f), (num3 == num4) ? Loc.Text("upgrade.all") : Loc.Format("upgrade.next", text), small); if (num3 >= num4) { GUI.Label(new Rect(555f, num6 + 36f, 225f, 52f), ((navigation.Selected == i) ? "> " : "") + Loc.Text("upgrade.max"), body); continue; } GUI.Label(new Rect(555f, num6 + 12f, 225f, 26f), Loc.Format("upgrade.price", num5), body); if (navigation.Button(new Rect(555f, num6 + 48f, 225f, 40f), i, Loc.Text((num2 < num5) ? "upgrade.insufficient" : "upgrade.buy"), !pending && num2 >= num5)) { Activate(i); } } GUI.Label(new Rect(25f, 478f, 770f, 36f), Loc.Text(pending ? "upgrade.pending" : status), small); if (navigation.Button(new Rect(25f, 525f, 360f, 32f), 4, Loc.Format("ui.language", ModLocalization.ChoiceLabel))) { Activate(4); } GUI.Label(new Rect(25f, 568f, 770f, 44f), ModMenuInput.Controls, small); GUI.matrix = matrix; } } private void OnDisable() { Close(); } private void OnDestroy() { Close(); if ((Object)(object)instance == (Object)(object)this) { instance = null; } } } internal static class UpgradeRules { internal static readonly int[][] Prices = new int[3][] { new int[5] { 40, 60, 80, 110, 150 }, new int[1] { 120 }, new int[2] { 120, 180 } }; internal const int HpPerLevel = 10; internal const float SpeedPerLevel = 0.05f; internal const int SlotsPerLevel = 1; internal const int BaseSlots = 3; internal static bool ValidKind(int kind) { if (kind >= 0) { return kind < Prices.Length; } return false; } internal static int Max(int kind) { if (!ValidKind(kind)) { return 0; } return Prices[kind].Length; } internal static int Clamp(int kind, int level) { return Math.Max(0, Math.Min(Max(kind), level)); } internal static int Price(int kind, int level) { if (!ValidKind(kind) || level < 0 || level >= Max(kind)) { return -1; } return Prices[kind][level]; } internal static bool CanBuy(int kind, int level, int expected, int gold) { int num = Price(kind, level); if (expected == level && num >= 0) { return gold >= num; } return false; } internal static int Capacity(int level) { return 3 + Clamp(2, level); } internal static float Speed(int level) { return 1f + (float)Clamp(1, level) * 0.05f; } } internal struct UpgradeLevels { internal int Hp; internal int Speed; internal int Inventory; internal int Get(int kind) { return kind switch { 1 => Speed, 0 => Hp, _ => Inventory, }; } internal void Increment(int kind) { switch (kind) { case 0: Hp++; break; case 1: Speed++; break; default: Inventory++; break; } } } internal enum ExtraId { Vacuum, Rift, IgnisRain, FishRain, SlipperyYuk, Orbit } internal sealed class ExtraDefinition { internal ExtraId Id; internal string School; internal string Name; internal string Ru; internal string Description; internal string RootEn; internal string RootRu; internal string EndingEn; internal string EndingRu; internal int Charges; internal float Regen; internal float Duration; internal float Radius; internal string Key => "YAPYAPEXP_EXTRA_" + Id.ToString().ToUpperInvariant(); internal ExtraDefinition(ExtraId id, string school, string name, string ru, string description, int charges, float regen, float duration, float radius, string root, string rootRu, string ending, string endingRu) { Id = id; School = school; Name = name; Ru = ru; Description = description; Charges = charges; Regen = regen; Duration = duration; Radius = radius; RootEn = root; RootRu = rootRu; EndingEn = ending; EndingRu = endingRu; } } internal static class ExtraCatalog { internal static readonly ExtraDefinition[] All = new ExtraDefinition[6] { new ExtraDefinition(ExtraId.Vacuum, "Wind", "VACUUM", "spell.vacuum.name", "spell.vacuum.description", 2, 16f, 5f, 3.5f, "AERO", "АЭРО", "VACUUM", "ВАКУУМ"), new ExtraDefinition(ExtraId.Rift, "Astral", "RIFT", "spell.rift.name", "spell.rift.description", 2, 18f, 12f, 0.85f, "ASTRAL", "АСТРАЛ", "RIFT", "РИФТ"), new ExtraDefinition(ExtraId.IgnisRain, "Fire", "IGNIS RAIN", "spell.ignisrain.name", "spell.ignisrain.description", 2, 22f, 4f, 2.5f, "IGNIS", "ИГНИС", "RAIN", "РЕЙН"), new ExtraDefinition(ExtraId.FishRain, "Grotesque", "FISH RAIN", "spell.fishrain.name", "spell.fishrain.description", 2, 18f, 4f, 2.5f, "YUK", "ФУ", "FISH", "ФИШ"), new ExtraDefinition(ExtraId.SlipperyYuk, "Grotesque", "SLIPPERY YUK", "spell.slipperyyuk.name", "spell.slipperyyuk.description", 2, 20f, 7f, 2.3f, "YUK", "ФУ", "SLIPPERY", "СЛИП"), new ExtraDefinition(ExtraId.Orbit, "Telekinesis", "ORBIT", "spell.orbit.name", "spell.orbit.description", 2, 20f, 6f, 2.2f, "TELE", "ТЕЛЕ", "ORBIT", "ОРБИТ") }; internal static ExtraDefinition Get(ExtraId id) { return All[(int)id]; } internal static string DetectSchool(string name, IEnumerable types) { string text = (name ?? "").ToLowerInvariant(); if (!text.Contains("wand")) { return null; } string[] array = new string[5] { "Telekinesis", "Grotesque", "Astral", "Fire", "Wind" }; foreach (string text2 in array) { if (text.Contains(text2.ToLowerInvariant())) { return text2; } } HashSet hashSet = new HashSet(types); if (hashSet.Contains("FishifySpell")) { return "Grotesque"; } if (hashSet.Contains("LavaSpell") || hashSet.Contains("FireSelfSpell")) { return "Fire"; } if (hashSet.Contains("TradeSpell") || hashSet.Contains("SwapSpell")) { return "Astral"; } if (hashSet.Contains("LockSpell") && hashSet.Contains("AntiGravitySpell")) { return "Telekinesis"; } if (hashSet.Contains("UpdraftSpell") || hashSet.Contains("TornadoSpell")) { return "Wind"; } return null; } } internal static class VanillaSpellExpansion { private static readonly FieldInfo Children = AccessTools.Field(typeof(VoiceSpell), "spells"); private static int suppress; internal static GameObject InstantiateDonor(Func create) { suppress++; try { return create(); } finally { suppress--; } } internal static void Install(Harmony harmony) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown try { harmony.Patch((MethodBase)AccessTools.Method(typeof(NetworkIdentity), "InitializeNetworkBehaviours", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VanillaSpellExpansion), "BeforeNetworkLayout", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.PropertyGetter(typeof(Spell), "CooldownProgress"), new HarmonyMethod(typeof(VanillaSpellExpansion), "Cooldown", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); SlipperySurface.Install(harmony); Plugin.Log.LogInfo((object)"Six vanilla spell extensions enabled; appended before Mirror component indexing."); } catch (Exception ex) { Plugin.Log.LogError((object)("Vanilla spell extension hooks: " + ex)); } } private static bool Cooldown(Spell __instance, ref float __result) { if (!(__instance is ExtraSpell)) { return true; } __result = 1f; return false; } private static void BeforeNetworkLayout(NetworkIdentity __instance) { //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown if (suppress != 0 || (Object)(object)__instance == (Object)null || __instance.netId != 0 || NetworkWandRegistry.IsOurAssetIdPublic(__instance.assetId)) { return; } VoiceSpell componentInChildren = ((Component)__instance).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null || (Object)(object)((Component)componentInChildren).GetComponentInParent() != (Object)(object)__instance || Children == null || !(Children.GetValue(componentInChildren) is Spell[] array) || array.Any((Spell x) => x is ExtraSpell)) { return; } string school = ExtraCatalog.DetectSchool(((Object)__instance).name, from x in array where (Object)(object)x != (Object)null select ((object)x).GetType().Name); ExtraDefinition[] array2 = ExtraCatalog.All.Where((ExtraDefinition x) => x.School == school).ToArray(); if (array2.Length == 0) { return; } if (((Component)__instance).GetComponentsInChildren(true).Length + array2.Length > 64) { Plugin.Log.LogError((object)("No Mirror component slots for additional spells: " + ((Object)__instance).name)); return; } List list = new List(array); List list2 = new List(); try { ExtraDefinition[] array3 = array2; foreach (ExtraDefinition extraDefinition in array3) { GameObject val = new GameObject(extraDefinition.Key); val.SetActive(false); val.transform.SetParent(((Component)__instance).transform, false); val.transform.SetAsLastSibling(); list2.Add(val); ExtraSpell extraSpell = val.AddComponent(); extraSpell.Configure(extraDefinition); list.Add((Spell)(object)extraSpell); } Children.SetValue(componentInChildren, list.ToArray()); foreach (GameObject item in list2) { item.SetActive(true); } Plugin.Log.LogInfo((object)("Extended " + ((Object)__instance).name + ": " + string.Join(", ", array2.Select((ExtraDefinition x) => x.Name)))); } catch (Exception ex) { Children.SetValue(componentInChildren, array); foreach (GameObject item2 in list2) { Object.DestroyImmediate((Object)(object)item2); } Plugin.Log.LogError((object)("Could not append vanilla spells: " + ex)); } } } public sealed class ExtraSpell : Spell { [SerializeField] private int extraId; internal ExtraZone Zone; internal ExtraVisual VisualA; internal ExtraVisual VisualB; internal ExtraDefinition Definition => ExtraCatalog.Get((ExtraId)extraId); protected override void Awake() { if ((Object)(object)base.spellData != (Object)null) { ((Spell)this).Awake(); } } internal void Configure(ExtraDefinition d) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) extraId = (int)d.Id; base.spellData = ScriptableObject.CreateInstance(); ((Object)base.spellData).name = d.Key; base.spellData.voiceCommandKey = d.Key; base.spellData.spellName = Loc.Text(d.Ru); base.spellData.charges = d.Charges; base.spellData.chargePerCast = 1; base.spellData.cooldown = 0f; base.spellData.chargesRegenPerInterval = 1; base.spellData.chargeRegenInterval = d.Regen; base.spellData.chargeRegenDelay = 0f; base.spellData.chargeCostPerSecondCast = 0; base.spellData.chargeColor = ExtraVisual.Tint(d.Id); } public override bool CanCast() { if ((Object)(object)base.spellData != (Object)null && CustomSpellSystem.IsHeld((Spell)(object)this)) { return ((Spell)this).CanCast(); } return false; } public override void OnSpellActivate() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || !((Spell)this).CanCast()) { return; } Vector3 point; Vector3 val; if (Definition.Id == ExtraId.Orbit) { point = ((Component)((Spell)this).CasterIdentity).transform.position; val = Vector3.up; } else { if (!SpellTargets.FirstHit((Spell)(object)this, (Definition.Id == ExtraId.Vacuum) ? 8f : 16f, out var first)) { return; } point = ((RaycastHit)(ref first)).point; val = ((RaycastHit)(ref first)).normal; if ((Definition.Id == ExtraId.SlipperyYuk && (val.y < 0.65f || (Object)(object)((RaycastHit)(ref first)).rigidbody != (Object)null)) || (Definition.Id == ExtraId.Rift && (Object)(object)((RaycastHit)(ref first)).rigidbody != (Object)null && !((RaycastHit)(ref first)).rigidbody.isKinematic)) { return; } } try { if (ExtraZone.TryCast(this, point, val)) { ((Spell)this).OnSpellActivate(); } } catch (Exception ex) { if ((Object)(object)Zone != (Object)null) { Zone.End(); } Plugin.Log.LogError((object)(Definition.Name + ": " + ex)); } } protected override void OnCasterIdentityChanged(NetworkIdentity oldCaster, NetworkIdentity newCaster) { if ((Object)(object)oldCaster != (Object)(object)newCaster) { if ((Object)(object)Zone != (Object)null) { Zone.End(); } ClearVisuals(); } ((Spell)this).OnCasterIdentityChanged(oldCaster, newCaster); } protected override void UserCode_RpcPlayEffect__SpellEffectType__Vector3__Quaternion(SpellEffectType effect, Vector3 point, Quaternion rotation) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if ((int)effect == 4) { ClearVisuals(); } else if ((int)effect == 1) { ExtraVisual.Refresh(ref VisualA, this, point, rotation); } else if ((int)effect == 3 && Definition.Id == ExtraId.Rift) { ExtraVisual.Refresh(ref VisualB, this, point, rotation); } else if ((int)effect == 3 && Definition.Id == ExtraId.IgnisRain) { ExtraVisual.FireDrop(point, rotation * Vector3.forward); } } internal void ClearVisuals() { if ((Object)(object)VisualA != (Object)null) { Object.Destroy((Object)(object)((Component)VisualA).gameObject); } if ((Object)(object)VisualB != (Object)null) { Object.Destroy((Object)(object)((Component)VisualB).gameObject); } VisualA = null; VisualB = null; } private void OnDestroy() { if ((Object)(object)Zone != (Object)null) { Zone.End(); } ClearVisuals(); if ((Object)(object)base.spellData != (Object)null) { Object.Destroy((Object)(object)base.spellData); } } } internal static class VoicePhraseBuilder { internal static bool TryBuild(Dictionary original, IEnumerable grammar, bool russian, out Dictionary phrases) { phrases = new Dictionary(StringComparer.Ordinal); HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); List occupied = new List(); foreach (KeyValuePair item in original) { if (!item.Key.StartsWith("YAPYAPEXP_", StringComparison.Ordinal) && item.Value != null) { occupied.Add(item.Value); string[] value = item.Value; foreach (string token in value) { AddToken(hashSet, token); } } } if (grammar != null) { foreach (string item2 in grammar) { AddToken(hashSet, item2); } } hashSet.RemoveWhere((string input) => occupied.Exists((string[] command) => NativeMatches(input, command))); if (hashSet.Count < 6) { return false; } List list = new List(hashSet); list.Sort(StringComparer.Ordinal); foreach (string item3 in Rank(list, russian ? "НИВА" : "NIVA")) { if (!BuildSchool(SpellCatalog.Frost, item3, list, occupied, russian, out var result)) { continue; } List list2 = new List(occupied); list2.AddRange(result.Values); foreach (string item4 in Rank(list, russian ? "АЛЕА" : "ALEA")) { if (Equal(item3, item4) || !BuildSchool(SpellCatalog.Chaos, item4, list, list2, russian, out var result2)) { continue; } foreach (KeyValuePair item5 in result) { phrases.Add(item5.Key, item5.Value); } foreach (KeyValuePair item6 in result2) { phrases.Add(item6.Key, item6.Value); } return true; } } return false; } private static bool BuildSchool(SpellDefinition[] definitions, string root, List tokens, List occupied, bool russian, out Dictionary result) { result = new Dictionary(StringComparer.Ordinal); List list = new List(occupied); foreach (SpellDefinition spellDefinition in definitions) { string[] array = null; foreach (string item in Rank(tokens, russian ? spellDefinition.EndingRu : spellDefinition.EndingEn)) { if (Equal(root, item)) { continue; } string[] array2 = new string[2] { root, item }; bool flag = false; foreach (string[] item2 in list) { if (Conflicts(array2, item2)) { flag = true; break; } } if (!flag) { array = array2; break; } } if (array == null) { return false; } result.Add(spellDefinition.Key, array); list.Add(array); } return true; } internal static bool Conflicts(string[] left, string[] right) { if (left == null || right == null || left.Length == 0 || right.Length == 0) { return false; } if (!NativeMatches(string.Join(" ", left), right) && !NativeMatches(string.Join(" ", right), left) && !ContainsWords(left, right)) { return ContainsWords(right, left); } return true; } internal static bool NativeMatches(string input, string[] words) { int startIndex = 0; foreach (string text in words) { if (string.IsNullOrEmpty(text)) { return false; } int num = input.IndexOf(text, startIndex, StringComparison.OrdinalIgnoreCase); if (num < 0) { return false; } startIndex = num + text.Length; } return words.Length != 0; } private static bool ContainsWords(string[] whole, string[] part) { List list = new List(whole); foreach (string word in part) { int num = list.FindIndex((string x) => Equal(x, word)); if (num < 0) { return false; } list.RemoveAt(num); } return true; } private static bool Equal(string a, string b) { return string.Equals(a, b, StringComparison.OrdinalIgnoreCase); } private static void AddToken(HashSet pool, string token) { if (string.IsNullOrWhiteSpace(token)) { return; } token = token.Trim().ToUpperInvariant(); if (token.Length < 2 || token.Length > 18) { return; } string text = token; foreach (char c in text) { if (!char.IsLetter(c) && c != '-' && c != '\'') { return; } } pool.Add(token); } private static List Rank(List tokens, string target) { List list = new List(tokens); list.Sort(delegate(string a, string b) { int num = Score(a, target).CompareTo(Score(b, target)); return (num == 0) ? string.CompareOrdinal(a, b) : num; }); return list; } private static int Score(string token, string target) { string text = token.ToUpperInvariant(); string text2 = target.ToUpperInvariant(); int[] array = new int[text2.Length + 1]; for (int i = 0; i < array.Length; i++) { array[i] = i; } for (int j = 1; j <= text.Length; j++) { int num = array[0]; array[0] = j; for (int k = 1; k <= text2.Length; k++) { int num2 = array[k]; array[k] = Math.Min(Math.Min(array[k] + 1, array[k - 1] + 1), num + ((text[j - 1] != text2[k - 1]) ? 1 : 0)); num = num2; } } return array[text2.Length] * 4 + Math.Abs(text.Length - text2.Length); } } internal static class VoiceVocabularyPatcher { private static readonly BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static readonly Dictionary ActivePhrases = new Dictionary(); internal static bool Russian { get; private set; } = true; internal static void PrepareFilesAndInstall(Harmony harmony) { Type type = typeof(Spell).Assembly.GetType("YAPYAP.VoiceManager"); if (type == null) { Plugin.Log.LogError((object)"VoiceManager was not found"); return; } Patch(harmony, type, "LoadLocalisationData", before: false); Patch(harmony, type, "ReloadLocalisation", before: false); Patch(harmony, type, "StartVosk", before: true); Patch(harmony, type, "SetLanguage", before: false); if (typeof(Object).IsAssignableFrom(type)) { Object[] array = Resources.FindObjectsOfTypeAll(type); for (int i = 0; i < array.Length; i++) { InjectIntoVoiceManager(array[i]); } } } private static void Patch(Harmony harmony, Type type, string name, bool before) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown MethodInfo[] methods = type.GetMethods(Fields); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != name)) { HarmonyMethod val = new HarmonyMethod(typeof(VoiceVocabularyPatcher).GetMethod("Refresh", BindingFlags.Static | BindingFlags.NonPublic)); harmony.Patch((MethodBase)methodInfo, before ? val : null, before ? null : val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } private static void Refresh(object __instance) { InjectIntoVoiceManager(__instance); } internal static string Phrase(string key) { if (!ActivePhrases.TryGetValue(key, out var value)) { return "—"; } return string.Join(" ", value); } internal static void InjectIntoVoiceManager(object manager) { if (manager == null) { return; } try { HashSet hashSet = new HashSet(); if (Get(manager, "_voskTranslators") is IEnumerable enumerable) { foreach (object item in enumerable) { if (item != null && hashSet.Add(item)) { Inject(item, active: false); } } } string[] array = new string[2] { "_defaultTranslator", "_defaultVoskTranslator" }; foreach (string name in array) { object obj = Get(manager, name); if (obj != null && hashSet.Add(obj)) { Inject(obj, active: false); } } object obj2 = Get(manager, "_currentVoskTranslator"); if (obj2 != null) { Inject(obj2, active: true); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Spell vocabulary: " + ex.Message)); } } private static void Inject(object translator, bool active) { if (!(Get(translator, "_commands") is IDictionary dictionary)) { return; } Dictionary dictionary2 = new Dictionary(StringComparer.Ordinal); bool flag = false; foreach (DictionaryEntry item in dictionary) { string text = item.Key as string; string[] array = item.Value as string[]; if (text == null || array == null || text.StartsWith("YAPYAPEXP_", StringComparison.Ordinal)) { continue; } dictionary2[text] = array; string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text2 = array2[i] ?? ""; foreach (char c in text2) { if (c >= 'Ѐ' && c <= 'ӿ') { flag = true; } } } } List list = new List(); if (Get(translator, "_grammar") is IEnumerable enumerable) { foreach (object item2 in enumerable) { if (item2 is string) { list.Add((string)item2); } } } if (!VoicePhraseBuilder.TryBuild(dictionary2, list, flag, out var phrases)) { if (active) { ActivePhrases.Clear(); } Plugin.Log.LogWarning((object)"Not enough non-conflicting voice tokens for both schools; custom voice entries unavailable."); return; } foreach (KeyValuePair item3 in ExtraVoicePhrases.Build(dictionary2, list, phrases, flag)) { phrases.Add(item3.Key, item3.Value); } bool flag2 = false; foreach (KeyValuePair item4 in phrases) { string[] array3 = dictionary[item4.Key] as string[]; flag2 |= array3 == null || string.Join(" ", array3) != string.Join(" ", item4.Value); dictionary[item4.Key] = item4.Value; } if (active) { Russian = flag; ActivePhrases.Clear(); foreach (KeyValuePair item5 in phrases) { ActivePhrases[item5.Key] = item5.Value; } } if (!flag2) { return; } foreach (KeyValuePair item6 in phrases) { Plugin.Log.LogInfo((object)("Incantation [" + (flag ? "RU" : "other") + "] " + item6.Key + " = " + string.Join(" ", item6.Value))); } } private static object Get(object target, string name) { FieldInfo field = target.GetType().GetField(name, Fields); if (!(field != null)) { return null; } return field.GetValue(target); } } internal static class WandPersistence { private sealed class PendingInventoryRestore { internal WandKind Kind; internal int PreferredSlot; internal float NextAttemptAt; internal int Attempts; } private const float RestoreDelay = 2.5f; private const float InventoryRetryInterval = 0.75f; private static bool _wasServerActive; private static bool _restoredThisSession; private static float _restoreAt; private static string _sessionWorldKey; private static float _suspendSavesUntil; private static bool _insideInventoryRestore; private static bool _saveRequestedAfterRestore; private static readonly List PendingInventory = new List(); private static string LegacySavePath => Path.Combine(Paths.ConfigPath, "YAPYAPExpanded_wands.txt"); private static string SavePath { get { string text = (string.IsNullOrEmpty(_sessionWorldKey) ? WorldContext.CurrentWorldKey : _sessionWorldKey); return Path.Combine(Paths.ConfigPath, "YAPYAPExpanded_wands_" + text + ".txt"); } } internal static void Update() { bool active = NetworkServer.active; if (active && !_wasServerActive) { _sessionWorldKey = null; _restoredThisSession = false; PendingInventory.Clear(); _suspendSavesUntil = 0f; _insideInventoryRestore = false; _saveRequestedAfterRestore = false; if (WorldContext.CurrentSaveSlot >= 0) { BeginWorldSession(); } else { Plugin.Log.LogWarning((object)"Custom wand persistence: server started before a save/world slot was captured; waiting"); } } if (active && string.IsNullOrEmpty(_sessionWorldKey) && WorldContext.CurrentSaveSlot >= 0) { BeginWorldSession(); } if (active && !string.IsNullOrEmpty(_sessionWorldKey)) { if (!_restoredThisSession && Time.unscaledTime >= _restoreAt) { _restoredThisSession = true; Restore(); } if (_restoredThisSession && PendingInventory.Count > 0) { UpdatePendingInventoryRestore(); } } if (!active && _wasServerActive) { _restoredThisSession = false; PendingInventory.Clear(); NetworkWandRegistry.ResetSessionCache(); _sessionWorldKey = null; _suspendSavesUntil = 0f; _insideInventoryRestore = false; _saveRequestedAfterRestore = false; } _wasServerActive = active; } private static void BeginWorldSession() { _sessionWorldKey = WorldContext.CurrentWorldKey; _restoredThisSession = false; PendingInventory.Clear(); _restoreAt = Time.unscaledTime + 2.5f; Plugin.Log.LogInfo((object)("Custom wand persistence: host session detected for " + _sessionWorldKey + "; restore scheduled")); } internal static void RequestSave(bool log) { if (_insideInventoryRestore) { _saveRequestedAfterRestore = true; } else { SaveNow(log); } } internal static void CaptureBeforeMassInventoryDrop(string reason) { if (NetworkServer.active && !string.IsNullOrEmpty(_sessionWorldKey)) { float unscaledTime = Time.unscaledTime; if (!(unscaledTime < _suspendSavesUntil)) { SaveNow(log: true); Plugin.Log.LogInfo((object)("Custom wand persistence: inventory snapshot captured before " + reason)); _suspendSavesUntil = unscaledTime + 5f; } } } internal static void SaveNow(bool log, bool allowEmpty = false) { //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: 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_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || string.IsNullOrEmpty(_sessionWorldKey)) { return; } if (_insideInventoryRestore) { _saveRequestedAfterRestore = true; return; } if (Time.unscaledTime < _suspendSavesUntil) { if (log) { Plugin.Log.LogInfo((object)"Custom wand persistence: save skipped during vanilla mass-drop/teardown guard"); } return; } try { List list = new List(); bool flag = false; NetworkIdentity[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (NetworkIdentity val in array) { if ((Object)(object)val == (Object)null || !val.isServer || !NetworkWandRegistry.IsOurAssetIdPublic(val.assetId) || !NetworkServer.spawned.ContainsKey(val.netId)) { continue; } flag = true; WandKind wandKind = ((val.assetId != 1497711432) ? WandKind.Frost : WandKind.Chaos); NetworkPuppetProp componentInChildren = ((Component)val).GetComponentInChildren(true); if (!((Object)(object)componentInChildren != (Object)null) || !componentInChildren.IsShopItem) { int num = (((Object)(object)componentInChildren != (Object)null) ? InventoryRestoreBridge.FindActualInventorySlot(componentInChildren) : (-1)); if (num >= 0) { list.Add("I|" + wandKind.ToString() + "|" + num.ToString(CultureInfo.InvariantCulture)); continue; } Transform transform = ((Component)val).transform; Vector3 position = transform.position; Quaternion rotation = transform.rotation; list.Add("W|" + wandKind.ToString() + "|" + F(position.x) + "|" + F(position.y) + "|" + F(position.z) + "|" + F(rotation.x) + "|" + F(rotation.y) + "|" + F(rotation.z) + "|" + F(rotation.w)); } } for (int j = 0; j < PendingInventory.Count; j++) { PendingInventoryRestore pendingInventoryRestore = PendingInventory[j]; list.Add("I|" + pendingInventoryRestore.Kind.ToString() + "|" + pendingInventoryRestore.PreferredSlot.ToString(CultureInfo.InvariantCulture)); } if (list.Count == 0 && !flag && !allowEmpty) { if (log) { Plugin.Log.LogInfo((object)"Custom wand save: no live custom wands; keeping previous world persistence file"); } return; } File.WriteAllLines(SavePath, list.ToArray()); if (log) { Plugin.Log.LogInfo((object)("Saved " + list.Count + " custom wand record(s) to " + SavePath)); } } catch (Exception ex) { Plugin.Log.LogError((object)("Custom wand save failed: " + ex)); } } private static void Restore() { //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { return; } TryMigrateLegacySaveForCurrentWorld(); if (!File.Exists(SavePath)) { Plugin.Log.LogInfo((object)("Custom wand persistence: no save file for " + _sessionWorldKey)); return; } try { string[] array = File.ReadAllLines(SavePath); int num = 0; int num2 = 0; foreach (string text in array) { if (string.IsNullOrWhiteSpace(text) || text.StartsWith("#", StringComparison.Ordinal)) { continue; } string[] array2 = text.Split('|'); WandKind result11; float result12; float result13; float result14; float result15; float result16; float result17; float result18; if (array2.Length == 9 && string.Equals(array2[0], "W", StringComparison.OrdinalIgnoreCase)) { if (Enum.TryParse(array2[1], ignoreCase: true, out var result) && TryF(array2[2], out var result2) && TryF(array2[3], out var result3) && TryF(array2[4], out var result4) && TryF(array2[5], out var result5) && TryF(array2[6], out var result6) && TryF(array2[7], out var result7) && TryF(array2[8], out var result8) && (Object)(object)NetworkWandRegistry.SpawnServerAt(result, new Vector3(result2, result3, result4), new Quaternion(result5, result6, result7, result8), restoredFromSave: true) != (Object)null) { num++; } } else if (array2.Length >= 2 && string.Equals(array2[0], "I", StringComparison.OrdinalIgnoreCase)) { if (Enum.TryParse(array2[1], ignoreCase: true, out var result9)) { int result10 = -1; if (array2.Length >= 3) { int.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out result10); } PendingInventory.Add(new PendingInventoryRestore { Kind = result9, PreferredSlot = result10, NextAttemptAt = Time.unscaledTime + 0.25f, Attempts = 0 }); num2++; } } else if (array2.Length == 8 && Enum.TryParse(array2[0], ignoreCase: true, out result11) && TryF(array2[1], out result12) && TryF(array2[2], out result13) && TryF(array2[3], out result14) && TryF(array2[4], out result15) && TryF(array2[5], out result16) && TryF(array2[6], out result17) && TryF(array2[7], out result18) && (Object)(object)NetworkWandRegistry.SpawnServerAt(result11, new Vector3(result12, result13, result14), new Quaternion(result15, result16, result17, result18), restoredFromSave: true) != (Object)null) { num++; } } Plugin.Log.LogInfo((object)("Custom wand persistence for " + _sessionWorldKey + ": restored " + num + " world wand(s), queued " + num2 + " inventory wand(s)")); } catch (Exception ex) { Plugin.Log.LogError((object)("Custom wand restore failed: " + ex)); } } private static void UpdatePendingInventoryRestore() { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (PendingInventory.Count == 0 || (Object)(object)Pawn.LocalInstance == (Object)null || !InventoryRestoreBridge.IsReady()) { return; } float unscaledTime = Time.unscaledTime; bool flag = false; for (int num = PendingInventory.Count - 1; num >= 0; num--) { PendingInventoryRestore pendingInventoryRestore = PendingInventory[num]; if (!(unscaledTime < pendingInventoryRestore.NextAttemptAt)) { int num2 = InventoryRestoreBridge.ResolveUsableSlot(pendingInventoryRestore.PreferredSlot); if (num2 < 0) { pendingInventoryRestore.Attempts++; pendingInventoryRestore.NextAttemptAt = unscaledTime + ((pendingInventoryRestore.Attempts > 10) ? 2f : 0.75f); } else { GameObject val = NetworkWandRegistry.SpawnServerAt(pendingInventoryRestore.Kind, ((Component)Pawn.LocalInstance).transform.position, Quaternion.identity, restoredFromSave: true); if ((Object)(object)val == (Object)null) { pendingInventoryRestore.Attempts++; pendingInventoryRestore.NextAttemptAt = unscaledTime + 0.75f; } else { bool flag2 = false; int actualSlot = -1; _insideInventoryRestore = true; try { flag2 = InventoryRestoreBridge.TryPlaceInInventory(val, num2, out actualSlot); } finally { _insideInventoryRestore = false; } if (flag2) { Plugin.Log.LogInfo((object)("Restored " + pendingInventoryRestore.Kind.ToString() + " wand through native PawnInventory slot " + actualSlot)); PendingInventory.RemoveAt(num); flag = true; } else { if (NetworkServer.active && (Object)(object)val != (Object)null) { NetworkServer.Destroy(val); } pendingInventoryRestore.Attempts++; pendingInventoryRestore.NextAttemptAt = unscaledTime + ((pendingInventoryRestore.Attempts > 10) ? 2f : 0.75f); if (pendingInventoryRestore.Attempts == 10) { Plugin.Log.LogWarning((object)("Inventory restore for " + pendingInventoryRestore.Kind.ToString() + " is still waiting; no world copy was left behind")); } } } } } } if (flag || _saveRequestedAfterRestore) { _saveRequestedAfterRestore = false; SaveNow(log: false); } } private static void TryMigrateLegacySaveForCurrentWorld() { if (File.Exists(SavePath) || !File.Exists(LegacySavePath)) { return; } try { File.Copy(LegacySavePath, SavePath, overwrite: false); string text = LegacySavePath + ".migrated_to_" + _sessionWorldKey; if (!File.Exists(text)) { File.Move(LegacySavePath, text); } else { File.Delete(LegacySavePath); } Plugin.Log.LogInfo((object)("Migrated old global custom-wand save into " + _sessionWorldKey + ". Each YAPYAP save slot now has its own wand file.")); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Legacy wand save migration skipped: " + ex.Message)); } } internal static void DeleteSaveForSlot(int slot) { if (slot < 0) { return; } try { string path = Path.Combine(Paths.ConfigPath, "YAPYAPExpanded_wands_slot_" + slot + ".txt"); if (File.Exists(path)) { File.Delete(path); Plugin.Log.LogInfo((object)("Deleted custom wand persistence together with YAPYAP save slot " + slot)); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not delete custom wand persistence for slot " + slot + ": " + ex.Message)); } } private static string F(float value) { return value.ToString("R", CultureInfo.InvariantCulture); } private static bool TryF(string value, out float result) { return float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out result); } } internal static class WorldContext { private static int _currentSaveSlot = -1; private static int _revision; internal static int CurrentSaveSlot => _currentSaveSlot; internal static int Revision => _revision; internal static string CurrentWorldKey { get { if (_currentSaveSlot < 0) { return "slot_unknown"; } return "slot_" + _currentSaveSlot; } } internal static void CaptureSlotObject(object source) { SetSlot(ResolveSlotFromObject(source)); } internal static void CaptureSlotArgs(object[] args) { SetSlot(ResolveSlotFromArgs(args)); } internal static int ResolveSlotFromArgs(object[] args) { if (args == null) { return -1; } for (int i = 0; i < args.Length; i++) { int num = ToNonNegativeInt(args[i]); if (num >= 0) { return num; } int num2 = ResolveSlotFromObject(args[i]); if (num2 >= 0) { return num2; } } return -1; } internal static int ResolveSlotFromObject(object obj) { if (obj == null) { return -1; } Type type = obj.GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; string[] array = new string[12] { "SlotIndex", "slotIndex", "_slotIndex", "CurrentSlot", "currentSlot", "_currentSlot", "SelectedSlot", "selectedSlot", "_selectedSlot", "SaveSlot", "saveSlot", "_saveSlot" }; foreach (string name in array) { PropertyInfo property = type.GetProperty(name, bindingAttr); if (property != null && property.GetIndexParameters().Length == 0) { try { object obj2 = ((property.GetGetMethod(nonPublic: true) != null && property.GetGetMethod(nonPublic: true).IsStatic) ? null : obj); int num = ToNonNegativeInt(property.GetValue(obj2, null)); if (num >= 0) { return num; } } catch { } } FieldInfo field = type.GetField(name, bindingAttr); if (!(field != null)) { continue; } try { int num2 = ToNonNegativeInt(field.GetValue(field.IsStatic ? null : obj)); if (num2 >= 0) { return num2; } } catch { } } FieldInfo[] array2; try { array2 = type.GetFields(bindingAttr); } catch { array2 = new FieldInfo[0]; } foreach (FieldInfo fieldInfo in array2) { if (fieldInfo.Name.IndexOf("slot", StringComparison.OrdinalIgnoreCase) < 0) { continue; } try { int num3 = ToNonNegativeInt(fieldInfo.GetValue(fieldInfo.IsStatic ? null : obj)); if (num3 >= 0) { return num3; } } catch { } } return -1; } internal static void SetSlotFromKnownValue(int slot) { SetSlot(slot); } private static void SetSlot(int slot) { if (slot >= 0 && _currentSaveSlot != slot) { _currentSaveSlot = slot; _revision++; Plugin.Log.LogInfo((object)("WorldContext: active save/world = slot " + slot)); } } private static int ToNonNegativeInt(object value) { if (value == null) { return -1; } try { if (value is int) { return ((int)value >= 0) ? ((int)value) : (-1); } if (value is short) { return ((short)value >= 0) ? ((short)value) : (-1); } if (value is int result) { return result; } if (value is uint) { return ((uint)value <= int.MaxValue) ? ((int)(uint)value) : (-1); } if (value is long) { return (int)(((long)value >= 0 && (long)value <= int.MaxValue) ? ((long)value) : (-1)); } } catch { } return -1; } } internal static class WorldContextPatcher { private static readonly HashSet Patched = new HashSet(); internal static void Install(Harmony harmony) { int num = 0; int num2 = 0; int num3 = 0; Type[] array; try { array = typeof(Pawn).Assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types; } if (array == null) { array = new Type[0]; } MethodInfo prefix = AccessTools.Method(typeof(WorldContextPatcher), "CaptureLoadPrefix", (Type[])null, (Type[])null); MethodInfo prefix2 = AccessTools.Method(typeof(WorldContextPatcher), "CaptureDeletePrefix", (Type[])null, (Type[])null); MethodInfo prefix3 = AccessTools.Method(typeof(WorldContextPatcher), "CaptureUiSlotPrefix", (Type[])null, (Type[])null); foreach (Type type in array) { if (type == null) { continue; } string a = type.Name ?? string.Empty; MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } if (string.Equals(a, "SaveManager", StringComparison.OrdinalIgnoreCase)) { foreach (MethodInfo methodInfo in methods) { if (methodInfo == null || methodInfo.ContainsGenericParameters || !HasSlotLikeParameter(methodInfo)) { continue; } string text = methodInfo.Name ?? string.Empty; if (text.IndexOf("load", StringComparison.OrdinalIgnoreCase) >= 0 && (text.IndexOf("save", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("slot", StringComparison.OrdinalIgnoreCase) >= 0)) { if (PatchSafe(harmony, methodInfo, prefix)) { num++; } } else if ((text.IndexOf("delete", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("remove", StringComparison.OrdinalIgnoreCase) >= 0) && (text.IndexOf("save", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("slot", StringComparison.OrdinalIgnoreCase) >= 0) && PatchSafe(harmony, methodInfo, prefix2)) { num2++; } } } if (!string.Equals(a, "UISaveSlot", StringComparison.OrdinalIgnoreCase)) { continue; } foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2 == null) && !methodInfo2.ContainsGenericParameters) { string text2 = methodInfo2.Name ?? string.Empty; if ((text2.IndexOf("load", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("play", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("select", StringComparison.OrdinalIgnoreCase) >= 0) && PatchSafe(harmony, methodInfo2, prefix3)) { num3++; } } } } Plugin.Log.LogInfo((object)("WorldContext patches installed | SaveManager load=" + num + " delete=" + num2 + " | UISaveSlot=" + num3)); if (num == 0 && num3 == 0) { Plugin.Log.LogWarning((object)"WorldContext: no save-slot entry method was found. Persistence will wait rather than share data between worlds."); } } private static bool PatchSafe(Harmony harmony, MethodBase original, MethodInfo prefix) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown if (original == null || prefix == null || Patched.Contains(original)) { return false; } try { harmony.Patch(original, new HarmonyMethod(prefix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Patched.Add(original); Plugin.Log.LogInfo((object)("WorldContext: patched " + original.DeclaringType.FullName + "." + original.Name)); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("WorldContext: could not patch " + original.DeclaringType.FullName + "." + original.Name + ": " + ex.Message)); return false; } } private static bool HasSlotLikeParameter(MethodInfo method) { ParameterInfo[] parameters; try { parameters = method.GetParameters(); } catch { return false; } for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if (parameterType == typeof(int) || parameterType == typeof(uint) || parameterType == typeof(short) || parameterType == typeof(byte) || parameterType == typeof(long)) { return true; } if ((parameters[i].Name ?? string.Empty).IndexOf("slot", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static void CaptureLoadPrefix(object[] __args) { WorldContext.CaptureSlotArgs(__args); } private static void CaptureDeletePrefix(object[] __args) { int num = WorldContext.ResolveSlotFromArgs(__args); if (num >= 0) { WandPersistence.DeleteSaveForSlot(num); } } private static void CaptureUiSlotPrefix(object __instance, object[] __args) { int num = WorldContext.ResolveSlotFromObject(__instance); if (num < 0) { num = WorldContext.ResolveSlotFromArgs(__args); } if (num >= 0) { WorldContext.SetSlotFromKnownValue(num); } } } internal static class LootRules { internal static readonly int[] Prices = new int[5] { 40, 80, 120, 160, 200 }; internal static readonly double[] Chances = new double[5] { 1.0, 0.6, 0.25, 0.08, 0.025 }; internal static double Chance(int price) { if (price <= Prices[0]) { return Chances[0]; } for (int i = 1; i < Prices.Length; i++) { if (price <= Prices[i]) { double num = (double)(price - Prices[i - 1]) / (double)(Prices[i] - Prices[i - 1]); return Chances[i - 1] + (Chances[i] - Chances[i - 1]) * num; } } return Chances[Chances.Length - 1]; } internal static bool Accept(int price, double roll) { if (roll >= 0.0) { return roll < Chance(price); } return false; } } internal static class WandLootBalance { internal static void Install() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown Harmony val = new Harmony("com.danya.yapyapexpanded.loot.v0102"); try { val.Patch((MethodBase)AccessTools.Method(typeof(RandomEntitySpawner), "SpawnObject", (Type[])null, (Type[])null), new HarmonyMethod(typeof(WandLootBalance), "RandomLoot", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.Method(typeof(NetworkSpawner), "SpawnObject", (Type[])null, (Type[])null), new HarmonyMethod(typeof(WandLootBalance), "NetworkLoot", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.Method(typeof(FrogStateMachine), "DropRewardItem", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(WandLootBalance), "FrogLoot", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"Wand loot balance ready: native selection retained, expensive free drops filtered by shop price."); } catch (Exception ex) { val.UnpatchSelf(); Plugin.Log.LogError((object)("Wand loot balance unavailable; native loot retained: " + ex)); } } private static bool Keep(GameObject prefab) { if (!NetworkServer.active || (Object)(object)prefab == (Object)null) { return true; } NetworkPuppetProp component = prefab.GetComponent(); if (!ShopEconomy.IsPricedWand(component)) { return true; } int price = ShopEconomy.EffectiveWandPrice(component); if (LootRules.Chance(price) >= 1.0) { return true; } bool result = LootRules.Accept(price, Random.value); Plugin.Log.LogDebug((object)("WAND LOOT " + ((Object)prefab).name + " | price=" + price + " | keep=" + result)); return result; } private static bool RandomLoot(RandomEntitySpawner __instance, SpawnEntity __0) { if ((Object)(object)((Component)__instance).GetComponentInParent() != (Object)null) { return true; } if (__0 != null) { return Keep(__0.prefab); } return true; } private static bool NetworkLoot(NetworkSpawner __instance, SpawnableObject __0, ref Transform __result) { if ((Object)(object)((Component)__instance).GetComponentInParent() != (Object)null || __0 == null || __0.isAI || Keep(__0.prefab)) { return true; } __result = null; return false; } internal static IEnumerable FrogLoot(IEnumerable code) { int count = 0; foreach (CodeInstruction instruction in code) { yield return instruction; if (instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo { Name: "item" } fieldInfo && fieldInfo.FieldType == typeof(NetworkIdentity)) { yield return new CodeInstruction(OpCodes.Call, (object)typeof(WandLootBalance).GetMethod("KeepReward", BindingFlags.Static | BindingFlags.NonPublic)); count++; } } if (count != 1) { throw new InvalidOperationException("Frog reward IL changed"); } } private static NetworkIdentity KeepReward(NetworkIdentity item) { if (!((Object)(object)item == (Object)null) && !Keep(((Component)item).gameObject)) { return null; } return item; } } internal static class Loc { internal static readonly Dictionary> Languages = Load(); internal static string Code = "ru"; private static Dictionary> Load() { Dictionary> dictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); Assembly assembly = typeof(Loc).Assembly; string[] manifestResourceNames = assembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (!text.StartsWith("YAPYAPExpanded.Localization.") || !text.EndsWith(".tsv")) { continue; } string key = text.Substring("YAPYAPExpanded.Localization.".Length).Replace(".tsv", ""); Dictionary dictionary2 = new Dictionary(StringComparer.Ordinal); using (StreamReader streamReader = new StreamReader(assembly.GetManifestResourceStream(text))) { string text2; while ((text2 = streamReader.ReadLine()) != null) { int num = text2.IndexOf('\t'); if (num > 0) { dictionary2[text2.Substring(0, num)] = text2.Substring(num + 1).Replace("\\n", "\n"); } } } dictionary[key] = dictionary2; } return dictionary; } internal static string For(string code, string key) { if (string.IsNullOrEmpty(key)) { return ""; } if (Languages.TryGetValue(code ?? "ru", out var value) && value.TryGetValue(key, out var value2)) { return value2; } if (Languages.TryGetValue("ru", out value) && value.TryGetValue(key, out value2)) { return value2; } return key; } internal static string Text(string key) { return For(Code, key); } internal static string Format(string key, params object[] args) { return string.Format((Code == "ru") ? CultureInfo.GetCultureInfo("ru-RU") : CultureInfo.InvariantCulture, Text(key), args); } internal static string Resolve(string choice, string gameLanguage) { if (string.Equals(choice, "Russian", StringComparison.OrdinalIgnoreCase)) { return "ru"; } if (string.Equals(choice, "English", StringComparison.OrdinalIgnoreCase)) { return "en"; } if (!string.Equals(gameLanguage, "English", StringComparison.OrdinalIgnoreCase)) { return "ru"; } return "en"; } } internal sealed class ModLocalization : MonoBehaviour { private static ConfigEntry language; private LocalisationManager manager; internal static string Choice => language?.Value ?? "Auto"; internal static string ChoiceLabel { get { if (!(Choice == "Auto")) { return Loc.Text((Choice == "Russian") ? "language.ru" : "language.en"); } return Loc.Text("ui.auto"); } } internal static void Install(ConfigFile config, Harmony harmony) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown language = config.Bind("Interface", "Language", "Auto", new ConfigDescription("Auto / Russian / English. Interface only; voice recognition keeps the game's voice language.", (AcceptableValueBase)(object)new AcceptableValueList(new string[3] { "Auto", "Russian", "English" }), Array.Empty())); harmony.Patch((MethodBase)AccessTools.PropertyGetter(typeof(Spell), "SpellName"), (HarmonyMethod)null, new HarmonyMethod(typeof(ModLocalization), "SpellName", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } internal static void Cycle() { if (language != null) { language.Value = ((Choice == "Auto") ? "Russian" : ((Choice == "Russian") ? "English" : "Auto")); Refresh(); } } internal static void Refresh() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) string gameLanguage = null; LocalisationManager val = default(LocalisationManager); if (Service.Get(ref val)) { Translator currentTranslator = val.CurrentTranslator; gameLanguage = ((currentTranslator != null) ? ((object)currentTranslator.Language/*cast due to .constrained prefix*/).ToString() : null); } Loc.Code = Loc.Resolve(Choice, gameLanguage); } private void Update() { LocalisationManager val = default(LocalisationManager); if (Service.Get(ref val) && manager != val) { if ((Object)(object)manager != (Object)null) { manager.OnLanguageChanged -= Changed; } manager = val; manager.OnLanguageChanged += Changed; } Refresh(); } private void Changed(Translator translator) { Refresh(); } private void OnDestroy() { if ((Object)(object)manager != (Object)null) { manager.OnLanguageChanged -= Changed; } } private static void SpellName(Spell __instance, ref string __result) { if (__instance is ExtraSpell extraSpell) { __result = Loc.Text(extraSpell.Definition.Ru); return; } SpellDefinition spellDefinition = CustomSpellSystem.Definition(__instance); if (spellDefinition != null) { __result = spellDefinition.LocalName; } } } internal sealed class MenuNavigation { internal int Selected; private int activationFrame = -100; private int heldDirection; private double nextRepeat; internal bool TakeActivation() { if (activationFrame == Time.frameCount) { return false; } activationFrame = Time.frameCount; return true; } internal static int Wrap(int value, int count) { if (count > 0) { return (value % count + count) % count; } return 0; } internal int Step(float x, float y, double now) { int num = ((!(Math.Abs(y) >= Math.Abs(x))) ? (((double)x > 0.5) ? 1 : (((double)x < -0.5) ? (-1) : 0)) : (((double)y > 0.5) ? (-1) : (((double)y < -0.5) ? 1 : 0))); if (num == 0) { heldDirection = 0; return 0; } if (num != heldDirection) { heldDirection = num; nextRepeat = now + 0.35; return num; } if (now < nextRepeat) { return 0; } nextRepeat = now + 0.14; return num; } internal void Update(int count) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) Vector2 navigate = ModMenuInput.Navigate; int num = Step(navigate.x, navigate.y, Time.unscaledTimeAsDouble); if (Input.GetKeyDown((KeyCode)9)) { num = ((!Input.GetKey((KeyCode)304)) ? 1 : (-1)); } Selected = Wrap(Selected + num, count); } internal bool Button(Rect rect, int index, string label, bool enabled = true) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if ((int)Event.current.type == 2 && ((Rect)(ref rect)).Contains(Event.current.mousePosition)) { Selected = index; } bool enabled2 = GUI.enabled; Color backgroundColor = GUI.backgroundColor; GUI.enabled = enabled; GUI.backgroundColor = (Color)((Selected == index) ? new Color(0.35f, 0.9f, 1f) : Color.white); bool result = GUI.Button(rect, ((Selected == index) ? "> " : "") + label); GUI.backgroundColor = backgroundColor; GUI.enabled = enabled2; return result; } } internal static class MenuInputRules { internal static bool ShouldRelease(int frames, double seconds, bool held) { if (frames > 1) { if (held) { return seconds >= 0.35; } return true; } return false; } internal static bool RestoreNavigation(bool previous, int previousMode, int currentMode, int padMode) { if (previousMode != currentMode) { return currentMode == padMode; } return previous; } } internal sealed class ModMenuInput : MonoBehaviour { internal static object Owner; private static object focusOwner; private static InputManager lockedManager; private static bool oldNav; private static bool providerWasEnabled; private static InputProvider provider; private static Pawn menuPawn; private static InputMode openingMode; private static double releasedAt; private static EventSystem events; private static GameObject oldSelection; private static GameObject pointerBlocker; private static CursorLockMode cursor; private static bool cursorVisible; private static int releasedFrame = -100; private static InputAction opener; private static InputAction[] menuActions; private static int openedFrame; internal static bool Busy { get { if (Owner == null && focusOwner == null) { return Time.frameCount <= releasedFrame + 1; } return true; } } internal static string OpenLabel { get { InputAction obj = opener; return ((obj != null) ? InputActionRebindingExtensions.GetBindingDisplayString(obj, (DisplayStringOptions)0, (string)null) : null) ?? "L3 + R3"; } } internal static bool OpenPressed { get { if (opener != null) { return opener.WasPressedThisFrame(); } return false; } } internal static bool CanOpen { get { if (!Busy && (Object)(object)InputManager.Instance != (Object)null && InputManager.Instance.HasFocus && !InputManager.Instance.IsInputLocked && (Object)(object)Pawn.LocalInstance != (Object)null && !Pawn.LocalInstance.IsDead) { return !Pawn.LocalInstance.IsExtracted; } return false; } } internal static bool UsingPad { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 if ((Object)(object)InputManager.Instance != (Object)null) { return (int)InputManager.Instance.InputMode == 1; } return false; } } internal static Vector2 Navigate { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //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) InputAction val = MenuAction(0); Vector2 result = ((val != null) ? val.ReadValue() : Vector2.zero); if (((Vector2)(ref result)).sqrMagnitude < 0.01f && Gamepad.current != null) { result = ((InputControl)(object)Gamepad.current.dpad).ReadValue(); if (((Vector2)(ref result)).sqrMagnitude < 0.01f) { result = ((InputControl)(object)Gamepad.current.leftStick).ReadValue(); } } return result; } } internal static bool Submit { get { if (Time.frameCount > openedFrame) { InputAction obj = MenuAction(1); if (obj == null) { return false; } return obj.WasPressedThisFrame(); } return false; } } internal static bool Back { get { if (Time.frameCount > openedFrame) { InputAction obj = MenuAction(2); if (obj == null || !obj.WasPressedThisFrame()) { return Input.GetKeyDown((KeyCode)27); } return true; } return false; } } internal static string Controls { get { object[] array = new object[3]; InputManager instance = InputManager.Instance; array[0] = Display((instance != null) ? instance.UINavigateAction : null); InputManager instance2 = InputManager.Instance; array[1] = Display((instance2 != null) ? instance2.SubmitAction : null); InputManager instance3 = InputManager.Instance; array[2] = Display((instance3 != null) ? instance3.CancelAction : null); return Loc.Format("ui.controls", array); } } internal static void Install(ConfigFile config) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) string value = config.Bind("Controller", "MenuModifier", "/leftStickPress", "Hold this button, then press MenuButton to open the mod menu.").Value; string value2 = config.Bind("Controller", "MenuButton", "/rightStickPress", "Mod menu button while MenuModifier is held.").Value; opener = new InputAction("YAPYAPExpandedMenu", (InputActionType)1, (string)null, (string)null, (string)null, (string)null); CompositeSyntax val = InputActionSetupExtensions.AddCompositeBinding(opener, "ButtonWithOneModifier", (string)null, (string)null); val = ((CompositeSyntax)(ref val)).With("Modifier", value, (string)null, (string)null); ((CompositeSyntax)(ref val)).With("Button", value2, (string)null, (string)null); opener.Enable(); } internal static bool Open(object owner) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected O, but got Unknown //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: 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) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) if (!CanOpen) { return false; } Owner = (focusOwner = owner); openedFrame = Time.frameCount; lockedManager = InputManager.Instance; menuPawn = Pawn.LocalInstance; cursor = Cursor.lockState; cursorVisible = Cursor.visible; openingMode = lockedManager.InputMode; try { provider = menuPawn.InputProvider; providerWasEnabled = (Object)(object)provider != (Object)null && ((Behaviour)provider).enabled; lockedManager.AddToInputFocusStack(owner); if (providerWasEnabled) { ((Behaviour)provider).enabled = false; } InputAction[] array = (InputAction[])(object)new InputAction[3] { lockedManager.UINavigateAction, lockedManager.SubmitAction, lockedManager.CancelAction }; menuActions = (InputAction[])(object)new InputAction[array.Length]; for (int i = 0; i < array.Length; i++) { if (array[i] != null && !array[i].enabled) { menuActions[i] = array[i].Clone(); menuActions[i].Enable(); } } events = EventSystem.current; if ((Object)(object)events != (Object)null) { oldNav = events.sendNavigationEvents; oldSelection = events.currentSelectedGameObject; events.sendNavigationEvents = false; events.SetSelectedGameObject((GameObject)null); } pointerBlocker = new GameObject("YAPYAPExpanded_MenuPointerBlocker", new Type[3] { typeof(RectTransform), typeof(Canvas), typeof(GraphicRaycaster) }); Canvas component = pointerBlocker.GetComponent(); component.renderMode = (RenderMode)0; component.sortingOrder = 32767; GameObject val = new GameObject("Blocker", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(pointerBlocker.transform, false); RectTransform component2 = val.GetComponent(); component2.anchorMin = Vector2.zero; component2.anchorMax = Vector2.one; Vector2 offsetMin = (component2.offsetMax = Vector2.zero); component2.offsetMin = offsetMin; Image component3 = val.GetComponent(); ((Graphic)component3).color = Color.clear; ((Graphic)component3).raycastTarget = true; Cursor.lockState = (CursorLockMode)0; Cursor.visible = !UsingPad; return true; } catch (Exception ex) { Plugin.Log.LogError((object)("Mod menu open failed; releasing input: " + ex)); Restore(); return false; } } private static InputAction MenuAction(int index) { InputManager instance = InputManager.Instance; if ((Object)(object)instance == (Object)null) { return null; } InputAction val = (InputAction)(index switch { 1 => instance.SubmitAction, 0 => instance.UINavigateAction, _ => instance.CancelAction, }); if (val != null && val.enabled) { return val; } if (Owner != null && menuActions != null && menuActions[index] == null && val != null) { menuActions[index] = val.Clone(); menuActions[index].Enable(); } InputAction[] array = menuActions; if (array == null) { return null; } return array[index]; } private static string Display(InputAction action) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (action == null) { return "—"; } InputManager instance = InputManager.Instance; string text = default(string); Sprite val = default(Sprite); instance.TryGetInputDisplay(instance.GetDefaultBinding(action, instance.InputMode), action, ref text, ref val); if (!string.IsNullOrEmpty(text)) { return text; } return action.name; } internal static void Close(object owner) { if (Owner == owner) { Owner = null; releasedFrame = Time.frameCount; releasedAt = Time.unscaledTimeAsDouble; } } private static void Cleanup(Action action) { try { action(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Mod menu input cleanup: " + ex.Message)); } } } private static void Restore() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected I4, but got Unknown //IL_0092: Expected I4, but got Unknown if (focusOwner == null) { return; } object owner = focusOwner; InputManager manager = lockedManager; InputProvider pawnProvider = provider; EventSystem system = events; GameObject selection = oldSelection; GameObject blocker = pointerBlocker; InputAction[] array = menuActions; bool restoreProvider = providerWasEnabled; bool navigation = (((Object)(object)manager != (Object)null) ? MenuInputRules.RestoreNavigation(oldNav, (int)openingMode, (int)manager.InputMode, 1) : oldNav); Owner = (focusOwner = null); lockedManager = null; menuPawn = null; provider = null; events = null; oldSelection = null; pointerBlocker = null; menuActions = null; releasedFrame = Time.frameCount; Cleanup(delegate { if ((Object)(object)blocker != (Object)null) { blocker.SetActive(false); Object.Destroy((Object)(object)blocker); } }); Cleanup(delegate { if ((Object)(object)pawnProvider != (Object)null && restoreProvider && ((Object)(object)InputManager.Instance == (Object)null || !InputManager.Instance.IsInputLocked)) { ((Behaviour)pawnProvider).enabled = true; } }); Cleanup(delegate { if ((Object)(object)manager != (Object)null) { manager.RemoveFromInputFocusStack(owner); } }); if (array != null) { InputAction[] array2 = array; foreach (InputAction val in array2) { if (val != null) { Cleanup((Action)val.Dispose); } } } Cleanup(delegate { if (!((Object)(object)system == (Object)null)) { system.sendNavigationEvents = navigation; if ((Object)(object)system.currentSelectedGameObject == (Object)null && (Object)(object)selection != (Object)null && selection.activeInHierarchy) { system.SetSelectedGameObject(selection); } } }); Cleanup(delegate { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)manager != (Object)null && (Object)(object)manager == (Object)(object)InputManager.Instance) { manager.UpdateCursorState(); } else if ((Object)(object)InputManager.Instance == (Object)null) { Cursor.lockState = cursor; Cursor.visible = cursorVisible; } }); } private void Update() { if (focusOwner == null) { return; } object obj = focusOwner; Behaviour val = (Behaviour)((obj is Behaviour) ? obj : null); if ((Object)(object)lockedManager == (Object)null || (Object)(object)lockedManager != (Object)(object)InputManager.Instance || (Object)(object)menuPawn == (Object)null || (Object)(object)menuPawn != (Object)(object)Pawn.LocalInstance || menuPawn.IsDead || menuPawn.IsExtracted || (focusOwner is Behaviour && ((Object)(object)val == (Object)null || !val.isActiveAndEnabled))) { Restore(); return; } if (Owner != null) { return; } InputAction obj2 = MenuAction(1); int num; if (obj2 == null || !obj2.IsPressed()) { InputAction obj3 = MenuAction(2); if (obj3 == null || !obj3.IsPressed()) { InputAction obj4 = opener; num = ((obj4 != null && obj4.IsPressed()) ? 1 : 0); goto IL_00cd; } } num = 1; goto IL_00cd; IL_00cd: bool held = (byte)num != 0; if (MenuInputRules.ShouldRelease(Time.frameCount - releasedFrame, Time.unscaledTimeAsDouble - releasedAt, held)) { Restore(); } } private void LateUpdate() { if (Owner != null) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = !UsingPad; if ((Object)(object)events != (Object)null) { events.sendNavigationEvents = false; } } } private void OnDisable() { Restore(); InputAction obj = opener; if (obj != null) { obj.Disable(); } } private void OnEnable() { InputAction obj = opener; if (obj != null) { obj.Enable(); } } private void OnDestroy() { Restore(); InputAction obj = opener; if (obj != null) { obj.Dispose(); } opener = null; } } internal static class ScaleBoostRules { internal const int FirstActiveLimit = 6; internal const int MaxActiveLimit = 16; internal const int UnlockedTier = 10; internal const float DespawnSeconds = 300f; internal const float MinimumDistance = 10f; internal static int ActiveLimit(int quotas) { return 6 + Math.Min(Math.Max(0, quotas), 10); } internal static float Interval(int quotas) { return (float)Math.Max(8.0, 20.0 - Math.Max(0.0, (double)quotas - 1.0) * 2.0); } internal static int PowerFloor(int quotas) { return ActiveLimit(quotas) * 4 + 10; } internal static float ScoreMultiplier(int quotas) { return (float)Math.Pow(1.135, Math.Max(0.0, quotas) + 1.0); } internal static int ScaleScore(int points, int quotas, bool questReward) { if (points <= 0 || questReward) { return points; } double num = Math.Floor((double)((float)points * ScoreMultiplier(quotas)) + 0.4); if (!(num >= 2147483647.0)) { return (int)num; } return int.MaxValue; } internal static bool IsJester(string name) { if (name != null) { return name.IndexOf("Jester", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } internal static int TypeLimit(int original, bool jester, int originalNonJesterSum, int quotas) { if (original <= 0) { return original; } if (jester) { return 2; } float num = (float)ActiveLimit(quotas) / (float)Math.Max(1, originalNonJesterSum); return Math.Max(1, (int)Math.Round((float)original * num)); } } internal static class QuestRewardScope { [ThreadStatic] private static int depth; internal static bool Active => depth > 0; internal static int Enter() { int result = depth; depth++; return result; } internal static void Leave(int previous) { depth = Math.Max(0, previous); } } internal static class ScaleBoostScore { internal static int Quotas { get { if (!((Object)(object)GameManager.Instance != (Object)null)) { return 0; } return Math.Max(0, GameManager.Instance.QuotaSessionsCompleted); } } internal static void Install() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Harmony val = new Harmony("com.danya.yapyapexpanded.scaleboostscore.v0120"); try { val.Patch((MethodBase)AccessTools.Method(typeof(DungeonTasks), "ServerOnTaskCompleted", (Type[])null, (Type[])null), Patch("BeginQuest"), (HarmonyMethod)null, (HarmonyMethod)null, Patch("EndQuest"), (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.Method(typeof(GameManager), "ModifyRoundScore", (Type[])null, (Type[])null), Patch("Score"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.Method(typeof(UIPopUp), "SpawnPopUpPoints", (Type[])null, (Type[])null), Patch("Popup"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"Scale Boost score enabled: 1.135^(completed quotas + 1); quest rewards and gold unchanged."); } catch (Exception ex) { val.UnpatchSelf(); Plugin.Log.LogError((object)("Scale Boost score hooks disabled: " + ex)); } static HarmonyMethod Patch(string name) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return new HarmonyMethod(typeof(ScaleBoostScore).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic)); } } private static void BeginQuest(out int __state) { __state = QuestRewardScope.Enter(); } private static Exception EndQuest(Exception __exception, int __state) { QuestRewardScope.Leave(__state); return __exception; } private static void Score(GameManager __instance, ref int addScore) { if (NetworkServer.active) { addScore = ScaleBoostRules.ScaleScore(addScore, __instance.QuotaSessionsCompleted, QuestRewardScope.Active); } } private static void Popup(ref int points) { if ((Object)(object)GameManager.Instance != (Object)null) { points = ScaleBoostRules.ScaleScore(points, Quotas, QuestRewardScope.Active); } } } }