using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FMODUnity; using HarmonyLib; using Mirror; using UnityEngine; using UnityEngine.AI; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using YAPYAP; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("YapyapFireBall")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("YapyapFireBall")] [assembly: AssemblyTitle("YapyapFireBall")] [assembly: AssemblyVersion("1.0.0.0")] namespace YapyapFireBallMod; internal enum ControlActionKind { HoldInput, Closer, Raise, SlamDown, Throw } internal enum ControlDirection { Forward, Back, Left, Right, Up, Down, UpLeft, UpRight, DownLeft, DownRight, ForwardLeft, ForwardRight, BackLeft, BackRight } internal sealed class ControlActionDefinition { internal string Key { get; } internal string[] Phrase { get; } internal ControlActionKind Kind { get; } internal ControlDirection Direction { get; } internal ControlActionDefinition(string key, string[] phrase, ControlActionKind kind, ControlDirection direction = ControlDirection.Forward) { Key = key; Phrase = phrase; Kind = kind; Direction = direction; } } internal static class ControlActionCatalog { internal static readonly ControlActionDefinition[] VoiceActions = new ControlActionDefinition[19] { new ControlActionDefinition("MOD_CONTROL_CLOSER", new string[1] { "CLOSER" }, ControlActionKind.Closer), new ControlActionDefinition("MOD_CONTROL_RAISE", new string[1] { "RAISE" }, ControlActionKind.Raise), new ControlActionDefinition("MOD_CONTROL_SLAM_DOWN", new string[2] { "SLAM", "DOWN" }, ControlActionKind.SlamDown), Throw("FORWARD", ControlDirection.Forward), Throw("BACK", ControlDirection.Back), Throw("LEFT", ControlDirection.Left), Throw("RIGHT", ControlDirection.Right), Throw("UP", ControlDirection.Up), Throw("DOWN", ControlDirection.Down), Throw("UP_LEFT", ControlDirection.UpLeft, "UP", "LEFT"), Throw("UP_RIGHT", ControlDirection.UpRight, "UP", "RIGHT"), Throw("DOWN_LEFT", ControlDirection.DownLeft, "DOWN", "LEFT"), Throw("DOWN_RIGHT", ControlDirection.DownRight, "DOWN", "RIGHT"), Throw("BOTTOM_LEFT", ControlDirection.DownLeft, "BOTTOM", "LEFT"), Throw("BOTTOM_RIGHT", ControlDirection.DownRight, "BOTTOM", "RIGHT"), Throw("FORWARD_LEFT", ControlDirection.ForwardLeft, "FORWARD", "LEFT"), Throw("FORWARD_RIGHT", ControlDirection.ForwardRight, "FORWARD", "RIGHT"), Throw("BACK_LEFT", ControlDirection.BackLeft, "BACK", "LEFT"), Throw("BACK_RIGHT", ControlDirection.BackRight, "BACK", "RIGHT") }; internal static IEnumerable> GetVoiceCommands() { ControlActionDefinition[] voiceActions = VoiceActions; foreach (ControlActionDefinition controlActionDefinition in voiceActions) { yield return new KeyValuePair(controlActionDefinition.Key, controlActionDefinition.Phrase); } } private static ControlActionDefinition Throw(string keySuffix, ControlDirection direction, params string[] directionWords) { string[] array = ((directionWords.Length != 0) ? directionWords : new string[1] { keySuffix }); string[] array2 = new string[array.Length + 1]; array2[0] = "THROW"; Array.Copy(array, 0, array2, 1, array.Length); return new ControlActionDefinition("MOD_CONTROL_THROW_" + keySuffix, array2, ControlActionKind.Throw, direction); } } public sealed class ControlActionSpell : Spell { [SerializeField] private ControlActionKind actionKind; [SerializeField] private ControlDirection direction; [SerializeField] private bool holdInputValue; internal ControlActionKind ActionKind => actionKind; internal ControlDirection Direction => direction; internal bool HoldInputValue => holdInputValue; internal bool IsHoldInputAction => ActionKind == ControlActionKind.HoldInput; internal void Configure(SpellData data, ControlActionKind actionKind, ControlDirection direction, bool holdInputValue = false) { base.spellData = data; this.actionKind = actionKind; this.direction = direction; this.holdInputValue = holdInputValue; base.OverrideSecret = true; } public override bool CanCast() { return false; } } public sealed class ControlInputRelay : MonoBehaviour { private static readonly FieldInfo AllSpellsField = AccessTools.Field(typeof(VoiceSpell), "allSpells"); private static readonly MethodInfo CastByIndexMethod = AccessTools.Method(typeof(VoiceSpell), "CmdCastSpellByIndex", (Type[])null, (Type[])null); [SerializeField] private VoiceSpell voiceSpell; private bool inputInitialized; private bool lastRPressed; private float nextSendRetry; internal bool ServerHoldActive { get; private set; } internal void Configure(VoiceSpell ownerVoiceSpell) { voiceSpell = ownerVoiceSpell; } internal void SetServerHold(bool active) { ServerHoldActive = active; if ((Object)(object)voiceSpell != (Object)null && voiceSpell.NetworkcurrentSpell is ControlSpell controlSpell) { controlSpell.SetHoldInput(active); } } private void Update() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)voiceSpell == (Object)null || (Object)(object)((Spell)voiceSpell).CasterIdentity == (Object)null || !((Spell)voiceSpell).CasterIdentity.isLocalPlayer) { inputInitialized = false; lastRPressed = false; return; } bool flag = Keyboard.current != null && ((ButtonControl)Keyboard.current[Plugin.ControlHoldKey]).isPressed; if ((!inputInitialized || flag != lastRPressed) && Time.unscaledTime >= nextSendRetry) { if (SendHoldState(flag)) { inputInitialized = true; lastRPressed = flag; } else { nextSendRetry = Time.unscaledTime + 0.25f; } } } private bool SendHoldState(bool pressed) { if (!(AllSpellsField.GetValue(voiceSpell) is List list)) { return false; } int num = list.FindIndex((Spell spell) => spell is ControlActionSpell controlActionSpell && (Object)(object)((Component)controlActionSpell).gameObject == (Object)(object)((Component)voiceSpell).gameObject && controlActionSpell.IsHoldInputAction && controlActionSpell.HoldInputValue == pressed); if (num < 0) { return false; } try { CastByIndexMethod.Invoke(voiceSpell, new object[2] { num, false }); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Control R input relay failed: " + ex.GetBaseException().Message)); return false; } } } internal static class ControlBootstrap { private static readonly FieldInfo VoiceSpellsField = AccessTools.Field(typeof(VoiceSpell), "spells"); private static readonly FieldInfo AllSpellsField = AccessTools.Field(typeof(VoiceSpell), "allSpells"); private static readonly FieldInfo NetworkAssetIdField = AccessTools.Field(typeof(NetworkIdentity), "_assetId"); private static readonly FieldInfo NetworkHasSpawnedField = AccessTools.Field(typeof(NetworkIdentity), "hasSpawned"); private static readonly FieldInfo SpellTagField = AccessTools.Field(typeof(BaseProjectile), "spellTag"); private static readonly FieldInfo PalmField = AccessTools.Field(typeof(ProjectileHand), "palmTransform"); private static readonly FieldInfo RotationSpeedField = AccessTools.Field(typeof(ProjectileHand), "rotationSpeed"); private static GameObject networkHandPrefab; private static SpellData controlSpellData; private static readonly Dictionary ActionSpellData = new Dictionary(StringComparer.Ordinal); internal static void Install(YapNetworkManager manager) { if ((Object)(object)manager == (Object)null) { return; } GameObject val = FindPrefab(manager, "PropWandOfMinorArcanes"); GameObject val2 = FindPrefab(manager, "SpectralHand"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)"Control was not installed: PropWandOfMinorArcanes or SpectralHand was not found."); return; } NetworkIdentity val3 = default(NetworkIdentity); if (((NetworkManager)manager).spawnPrefabs.Any((GameObject prefab) => (Object)(object)prefab != (Object)null && prefab.TryGetComponent(ref val3) && val3.assetId == 3229223441u)) { Plugin.Log.LogError((object)$"Control hand asset ID collision: {3229223441u}. Control will not install."); return; } VoiceSpell component = val.GetComponent(); GrabSpell component2 = val.GetComponent(); ProjectileHand component3 = val2.GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { Plugin.Log.LogError((object)"Control was not installed: VoiceSpell, GrabSpell, or ProjectileHand is missing."); return; } EnsureRuntimeData(component2); EnsureHandPrefab(val2, component3); EnsureSpellsOnWand(val, component); } private static GameObject FindPrefab(YapNetworkManager manager, string name) { return ((IEnumerable)((NetworkManager)manager).spawnPrefabs).FirstOrDefault((Func)((GameObject prefab) => (Object)(object)prefab != (Object)null && string.Equals(((Object)prefab).name, name, StringComparison.Ordinal))); } private static void EnsureRuntimeData(GrabSpell grabSpell) { //IL_00ac: 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) if ((Object)(object)controlSpellData == (Object)null) { controlSpellData = Object.Instantiate(((Spell)grabSpell).SpellData); ((Object)controlSpellData).name = "SD_ARC_CONTROL_MOD"; controlSpellData.spellName = "CONTROL"; controlSpellData.voiceCommandKey = "MOD_SPELL_ARC_CONTROL"; controlSpellData.cooldown = 2f; controlSpellData.charges = 3; controlSpellData.chargePerCast = 1; controlSpellData.chargeCostPerSecondCast = 0; controlSpellData.chargeRegenInterval = 6f; controlSpellData.chargesRegenPerInterval = 1; controlSpellData.chargeRegenDelay = 0.5f; controlSpellData.spawnLocation = (SpawnLocation)0; controlSpellData.spawnOffset = Vector3.zero; controlSpellData.applyLookTransform = true; controlSpellData.spawnDelay = 0f; } } private static void EnsureHandPrefab(GameObject vanillaHandPrefab, ProjectileHand vanillaHand) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)networkHandPrefab != (Object)null) { controlSpellData.objectToSpawnPrefab = networkHandPrefab; return; } bool activeSelf = vanillaHandPrefab.activeSelf; try { vanillaHandPrefab.SetActive(false); networkHandPrefab = Object.Instantiate(vanillaHandPrefab); } finally { vanillaHandPrefab.SetActive(activeSelf); } ((Object)networkHandPrefab).name = "ControlSpectralHandMod"; networkHandPrefab.SetActive(false); Object.DontDestroyOnLoad((Object)(object)networkHandPrefab); NetworkIdentity component = networkHandPrefab.GetComponent(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("The cloned SpectralHand has no NetworkIdentity."); } NetworkAssetIdField.SetValue(component, 3229223441u); NetworkHasSpawnedField.SetValue(component, false); component.sceneId = 0uL; NetworkBehaviour[] components = networkHandPrefab.GetComponents(); foreach (NetworkBehaviour val in components) { if (((object)val).GetType().Name.IndexOf("NetworkTransform", StringComparison.Ordinal) >= 0) { val.syncDirection = (SyncDirection)0; } } ProjectileHand component2 = networkHandPrefab.GetComponent(); ((Behaviour)component2).enabled = false; ControlProjectileHand obj = networkHandPrefab.GetComponent() ?? networkHandPrefab.AddComponent(); ProjectileData projectileData = ((BaseProjectile)component2).ProjectileData; SpellData ownerSpellData = controlSpellData; object ownerSpellTag = (object)/*isinst with value type is only supported in some contexts*/; object? value = PalmField.GetValue(component2); obj.Configure(projectileData, ownerSpellData, (GameplayTag)ownerSpellTag, component2, (Transform)((value is Transform) ? value : null), (float)RotationSpeedField.GetValue(component2), Plugin.ControlHoldStrength); controlSpellData.objectToSpawnPrefab = networkHandPrefab; Plugin.Log.LogInfo((object)$"Prepared Control spectral hand with asset ID {3229223441u}."); } private static void EnsureSpellsOnWand(GameObject wandPrefab, VoiceSpell voiceSpell) { ControlSpell controlSpell = wandPrefab.GetComponent() ?? wandPrefab.AddComponent(); controlSpell.Configure(controlSpellData); ((Behaviour)controlSpell).enabled = true; (wandPrefab.GetComponent() ?? wandPrefab.AddComponent()).Configure(voiceSpell); List list = ((VoiceSpellsField.GetValue(voiceSpell) as Spell[]) ?? Array.Empty()).ToList(); if (!list.Contains((Spell)(object)controlSpell)) { list.Add((Spell)(object)controlSpell); } AddActionSpell(wandPrefab, list, controlSpellData, "MOD_CONTROL_R_PRESS", Array.Empty(), ControlActionKind.HoldInput, ControlDirection.Forward, holdInputValue: true); AddActionSpell(wandPrefab, list, controlSpellData, "MOD_CONTROL_R_RELEASE", Array.Empty(), ControlActionKind.HoldInput, ControlDirection.Forward); ControlActionDefinition[] voiceActions = ControlActionCatalog.VoiceActions; foreach (ControlActionDefinition controlActionDefinition in voiceActions) { AddActionSpell(wandPrefab, list, controlSpellData, controlActionDefinition.Key, controlActionDefinition.Phrase, controlActionDefinition.Kind, controlActionDefinition.Direction); } VoiceSpellsField.SetValue(voiceSpell, list.ToArray()); Plugin.Log.LogInfo((object)($"Added Control, R input relay, and {ControlActionCatalog.VoiceActions.Length} " + $"voice actions to PropWandOfMinorArcanes ({list.Count} entries).")); } private static void AddActionSpell(GameObject wandPrefab, List spells, SpellData template, string key, string[] phrase, ControlActionKind actionKind, ControlDirection direction, bool holdInputValue = false) { //IL_00e8: 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) ControlActionSpell controlActionSpell = wandPrefab.GetComponents().FirstOrDefault((ControlActionSpell action) => action.ActionKind == actionKind && action.Direction == direction && action.HoldInputValue == holdInputValue && (Object)(object)((Spell)action).SpellData != (Object)null && string.Equals(((Object)((Spell)action).SpellData).name, "SD_ARC_" + key, StringComparison.Ordinal)); if ((Object)(object)controlActionSpell == (Object)null) { controlActionSpell = wandPrefab.AddComponent(); } if (!ActionSpellData.TryGetValue(key, out var value)) { value = Object.Instantiate(template); ((Object)value).name = "SD_ARC_" + key; value.spellName = ((phrase.Length == 0) ? key : string.Join(" ", phrase)); value.voiceCommandKey = ((phrase.Length == 0) ? string.Empty : key); value.cooldown = 0f; value.charges = -1; value.chargePerCast = 0; value.chargeCostPerSecondCast = 0; value.chargesRegenPerInterval = 0; value.objectToSpawnPrefab = null; value.castingAnimationType = (CastingAnimationType)0; value.castingLoopAnimationType = (CastingLoopAnimationType)0; ActionSpellData.Add(key, value); } controlActionSpell.Configure(value, actionKind, direction, holdInputValue); ((Behaviour)controlActionSpell).enabled = true; if (!spells.Contains((Spell)(object)controlActionSpell)) { spells.Add((Spell)(object)controlActionSpell); } } internal static void RegisterClientSpawnHandler() { //IL_0033: 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_0049: Expected O, but got Unknown //IL_0049: Expected O, but got Unknown if ((Object)(object)networkHandPrefab == (Object)null) { Plugin.Log.LogWarning((object)"Cannot register Control client spawn handler: hand prefab is not prepared."); return; } NetworkClient.UnregisterSpawnHandler(3229223441u); NetworkClient.RegisterSpawnHandler(3229223441u, new SpawnHandlerDelegate(SpawnClientHand), new UnSpawnDelegate(UnspawnClientHand)); Plugin.Log.LogInfo((object)$"Registered Control client spawn handler for asset ID {3229223441u}."); } private static GameObject SpawnClientHand(SpawnMessage message) { //IL_0005: 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) GameObject obj = Object.Instantiate(networkHandPrefab, message.position, message.rotation); obj.SetActive(true); return obj; } private static void UnspawnClientHand(GameObject instance) { if ((Object)(object)instance != (Object)null) { Object.Destroy((Object)(object)instance); } } internal static bool ShouldRunOriginalCastCommand(VoiceSpell voiceSpell, int index) { if (!(AllSpellsField.GetValue(voiceSpell) is List list) || index < 0 || index >= list.Count || !(list[index] is ControlActionSpell controlActionSpell)) { return true; } if (controlActionSpell.IsHoldInputAction) { ((Component)voiceSpell).GetComponent()?.SetServerHold(controlActionSpell.HoldInputValue); Plugin.Log.LogDebug((object)$"Server received Control R state: {controlActionSpell.HoldInputValue}."); return false; } if (!(voiceSpell.NetworkcurrentSpell is ControlSpell controlSpell)) { return false; } if (controlSpell.TryApplyAction(controlActionSpell.ActionKind, controlActionSpell.Direction)) { voiceSpell.NetworkcurrentSpell = null; ((Spell)voiceSpell).NetworkisCasting = false; voiceSpell.StopPrimingAnimation(); } return false; } internal static bool ShouldRunOriginalStopCommand(VoiceSpell voiceSpell) { if (voiceSpell.NetworkcurrentSpell is ControlSpell) { Plugin.Log.LogDebug((object)"Ignored duplicate CONTROL voice-stop; R release owns Control cancellation."); return false; } return true; } } [HarmonyPatch(typeof(VoiceSpell), "UserCode_CmdCastSpellByIndex__Int32__Boolean")] internal static class ControlThrowCommandPatch { [HarmonyPrefix] private static bool Prefix(VoiceSpell __instance, int index) { return ControlBootstrap.ShouldRunOriginalCastCommand(__instance, index); } } [HarmonyPatch(typeof(VoiceSpell), "UserCode_CmdStopCurrentSpell")] internal static class ControlDuplicateVoiceStopPatch { [HarmonyPrefix] private static bool Prefix(VoiceSpell __instance) { return ControlBootstrap.ShouldRunOriginalStopCommand(__instance); } } [HarmonyPatch(typeof(NetworkPuppetWandProp), "SetSpellCasting")] internal static class ControlMouseIsolationPatch { [HarmonyPrefix] private static bool Prefix(NetworkPuppetWandProp __instance, bool wantsToCast) { if (NetworkServer.active) { Spell spell = __instance.Spell; VoiceSpell val = (VoiceSpell)(object)((spell is VoiceSpell) ? spell : null); if (val != null && val.NetworkcurrentSpell is ControlSpell) { __instance.NetworkisCastingSpell = wantsToCast; return false; } } return true; } } public sealed class ControlProjectileHand : BaseProjectile { private enum ControlState { Flying, Captured, Returning, Holding, Ending } private static readonly MethodInfo ReachRpc = AccessTools.Method(typeof(ProjectileHand), "RpcPlayReachAnimation", (Type[])null, (Type[])null); private static readonly MethodInfo GrabRpc = AccessTools.Method(typeof(ProjectileHand), "RpcPlayGrabAnimation", (Type[])null, (Type[])null); private static readonly MethodInfo PullRpc = AccessTools.Method(typeof(ProjectileHand), "RpcPlayPullAnimation", (Type[])null, (Type[])null); private static readonly MethodInfo ObstacleRpc = AccessTools.Method(typeof(ProjectileHand), "RpcPlayHitObstacleAnim", (Type[])null, (Type[])null); [SerializeField] private ProjectileHand visualBridge; [SerializeField] private Transform palmTransform; [SerializeField] private float rotationSpeed = 180f; [SerializeField] private float captureInputWindow = 5f; [SerializeField] private float returnSpeed = 8f; [SerializeField] private float holdStrength = 8f; [SerializeField] private float itemHoldDistance = 0.5f; [SerializeField] private float playerHoldDistance = 1f; [SerializeField] private float enemyHoldDistance = 2.5f; private ControlState state; private Rigidbody grabbedBody; private Pawn grabbedPawn; private NpcBehaviour grabbedNpc; private SpringJoint grabJoint; private GameObject anchorPoint; private Collider[] handColliders; private Collider[] grabbedColliders; private Collider casterCapsule; private Vector3 localGrabPoint; private float captureDeadline; private float nextPawnCorrectionTime; private float holdDistanceAdjustment; private float raisedHeight; private float slamUntil; private bool wasThrown; private bool npcNavigationDisabled; private bool ignoringCasterCollision; public bool HasGrabbedTarget { get { if ((Object)(object)grabbedBody != (Object)null) { if (state != ControlState.Captured && state != ControlState.Returning) { return state == ControlState.Holding; } return true; } return false; } } internal Rigidbody GrabbedBody => grabbedBody; internal NetworkIdentity ControlCaster => base.Caster; internal void Configure(ProjectileData data, SpellData ownerSpellData, GameplayTag ownerSpellTag, ProjectileHand bridge, Transform palm, float rotateSpeed, float configuredHoldStrength) { base.projectileData = data; base.spellData = ownerSpellData; base.spellTag = ownerSpellTag; visualBridge = bridge; palmTransform = palm; rotationSpeed = rotateSpeed; holdStrength = configuredHoldStrength; base.ttl = 5f; base.ignoreCaster = true; base.delayProcessObstacles = true; } public override void Initialize(NetworkIdentity caster, Spell ownerSpell) { ((BaseProjectile)this).Initialize(caster, ownerSpell); state = ControlState.Flying; handColliders = ((Component)this).GetComponents(); } public override void Fire(Vector3 direction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((BaseProjectile)this).Fire(direction); if (((NetworkBehaviour)this).isServer) { state = ControlState.Flying; InvokeVisualRpc(ReachRpc); } } protected override void FixedUpdate() { //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_0046: 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_0062: 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_00a2: 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_00e6: 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_0114: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: 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_0188: 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_0194: 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) //IL_01a8: 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_0177: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).isServer || state == ControlState.Ending || !base.hasBeenFired) { return; } if (state == ControlState.Flying) { ((BaseProjectile)this).FixedUpdate(); if (((BaseProjectile)this).Direction != Vector3.zero) { ((Component)this).transform.rotation = Quaternion.RotateTowards(((Component)this).transform.rotation, Quaternion.LookRotation(((BaseProjectile)this).Direction), rotationSpeed * Time.fixedDeltaTime); } return; } if ((Object)(object)grabbedBody == (Object)null) { DropAndDestroy(); return; } if (state == ControlState.Captured) { ((Component)this).transform.position = ((Component)grabbedBody).transform.TransformPoint(localGrabPoint); if (IsHoldInputActive()) { BeginReturn(); } else if (Time.time >= captureDeadline) { DropAndDestroy(); } return; } if (!IsHoldInputActive()) { DropAndDestroy(); return; } Vector3 aimDirection; Vector3 safePoint = GetSafePoint(out aimDirection); float num = ((Time.time < slamUntil) ? (returnSpeed * 2f) : returnSpeed); float num2 = Vector3.Distance(((Component)this).transform.position, safePoint); if (Time.time >= slamUntil) { num = Mathf.Lerp(1f, num, Mathf.Clamp01(num2 / 1.5f)); } ((Component)this).transform.position = Vector3.MoveTowards(((Component)this).transform.position, safePoint, num * Time.fixedDeltaTime); if (aimDirection != Vector3.zero) { ((Component)this).transform.rotation = Quaternion.LookRotation(aimDirection); } PullTargetToward(((Component)this).transform.position); bool flag = BrakeTargetAtSafePoint(safePoint, aimDirection); state = ((Vector3.Distance(((Component)this).transform.position, safePoint) <= 0.05f && flag) ? ControlState.Holding : ControlState.Returning); } protected override bool ShouldDestroyOnTargetHit() { return false; } protected override bool ShouldDestroyOnWallHit() { return false; } protected override void OnTriggerEnter(Collider other) { //IL_015a: 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) if (!((NetworkBehaviour)this).isServer || state != ControlState.Flying || !base.hasBeenFired || (Object)(object)base.projectileData == (Object)null || (other.isTrigger && !((Component)other).CompareTag("TriggerPhysical")) || ((Component)other).gameObject.CompareTag("IgnoreCollision") || ((Component)other).gameObject.CompareTag("EntityBlocker") || base.hasHit || Time.time - base.spawnTime < base.projectileData.spawnInvulnerability || ((Object)(object)base.Caster != (Object)null && ((Component)other).transform.IsChildOf(((Component)base.Caster).transform))) { return; } NetworkIdentity val = ((Component)other).GetComponent() ?? ((Component)other).GetComponentInParent(); Rigidbody attachedRigidbody = other.attachedRigidbody; int num = 1 << ((Component)other).gameObject.layer; if ((((LayerMask)(ref base.projectileData.wallLayer)).value & num) != 0 || (Object)(object)attachedRigidbody == (Object)null) { if (base.delayProcessObstacles) { base.hitObstacleFlag = true; base.hitObstacleFlagCollider = other; } else { ((BaseProjectile)this).OnWallHit(other); } } else if ((((LayerMask)(ref base.projectileData.targetLayer)).value & num) != 0) { ((BaseProjectile)this).OnTargetHit(other, attachedRigidbody, val); if (state == ControlState.Captured && (Object)(object)base.OwnerSpell != (Object)null) { base.OwnerSpell.RpcPlayEffect((SpellEffectType)3, ((Component)this).transform.position, ((Component)this).transform.rotation); } } } protected override void OnWallHit(Collider wall) { if (((NetworkBehaviour)this).isServer && state == ControlState.Flying) { ((BaseProjectile)this).OnWallHit(wall); state = ControlState.Ending; base.stopMoving = true; InvokeVisualRpc(ObstacleRpc); ((MonoBehaviour)this).StartCoroutine(DestroyAfterDelay()); } } protected override void OnTargetHit(Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity) { //IL_00e8: 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_00ed: 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_00fb: 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) if (!((NetworkBehaviour)this).isServer || state != ControlState.Flying || (Object)(object)targetRigidbody == (Object)null || (Object)(object)((Component)targetRigidbody).GetComponent() != (Object)null || (Object)(object)((Component)targetRigidbody).GetComponent() != (Object)null) { return; } UnstickTrigger val = default(UnstickTrigger); if (targetRigidbody.isKinematic && !((Component)targetRigidbody).TryGetComponent(ref val)) { ((BaseProjectile)this).OnWallHit(target); return; } grabbedBody = targetRigidbody; grabbedPawn = ((Component)targetRigidbody).GetComponent() ?? ((Component)targetRigidbody).GetComponentInParent() ?? (((Object)(object)targetIdentity == (Object)null) ? null : ((Component)targetIdentity).GetComponent()); grabbedNpc = ((Component)targetRigidbody).GetComponent() ?? ((Component)targetRigidbody).GetComponentInParent() ?? (((Object)(object)targetIdentity == (Object)null) ? null : ((Component)targetIdentity).GetComponent()); Transform val2 = (((Object)(object)palmTransform == (Object)null) ? ((Component)this).transform : palmTransform); Vector3 val3 = (target.isTrigger ? ((Component)target).transform.position : target.ClosestPoint(val2.position)); localGrabPoint = ((Component)grabbedBody).transform.InverseTransformPoint(val3); grabbedColliders = ((Component)grabbedBody).GetComponentsInChildren(true); captureDeadline = Time.time + captureInputWindow; base.stopMoving = true; state = ControlState.Captured; SetHandCollidersEnabled(enabled: false); if ((Object)(object)targetIdentity != (Object)null) { HandleTargetTags(targetIdentity); } InvokeVisualRpc(GrabRpc); Plugin.Log.LogDebug((object)("Control captured " + GetTargetKind() + "; waiting for R until " + $"{captureDeadline:0.00}.")); if (IsHoldInputActive()) { BeginReturn(); } } private bool IsHoldInputActive() { if (base.OwnerSpell is ControlSpell controlSpell) { return controlSpell.HoldInputActive; } return false; } private void BeginReturn() { if (state == ControlState.Captured && !((Object)(object)grabbedBody == (Object)null)) { UnstickTrigger val = default(UnstickTrigger); if (((Component)grabbedBody).TryGetComponent(ref val)) { val.TryUnstick(base.Caster); } if ((Object)(object)grabbedPawn == (Object)null && (Object)(object)grabbedNpc == (Object)null) { CreateGrabJoint(); } SetCasterCollisionIgnored(ignore: true); if ((Object)(object)grabbedNpc != (Object)null && (Object)(object)grabbedNpc.npcToggler != (Object)null && grabbedNpc.npcToggler.NetworknavigationEnabled) { grabbedNpc.npcToggler.SvDisableNavigation(false); npcNavigationDisabled = true; } state = ControlState.Returning; InvokeVisualRpc(PullRpc); Plugin.Log.LogDebug((object)("Control returning " + GetTargetKind() + " to " + $"{GetSafeHoldDistance():0.0}m.")); } } private void PullTargetToward(Vector3 targetPoint) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0020: 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_00b6: 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_00cc: 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_00e9: 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_0053: 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_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_0079: 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_0086: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)grabbedBody == (Object)null) { return; } Vector3 val = targetPoint - grabbedBody.worldCenterOfMass; if ((Object)(object)grabbedPawn != (Object)null) { if (Time.time >= nextPawnCorrectionTime) { nextPawnCorrectionTime = Time.time + 0.1f; Vector3 val2 = Vector3.ClampMagnitude(val * 2.5f, returnSpeed * 0.5f) - grabbedBody.linearVelocity; grabbedPawn.SvAddExternalImpulse(Vector3.ClampMagnitude(val2 * 0.5f, holdStrength * 0.5f)); } } else if ((Object)(object)grabbedNpc != (Object)null) { Vector3 val3 = Vector3.ClampMagnitude(val * 2.5f, returnSpeed * 0.5f); grabbedNpc.AddForce(val3 * Mathf.Max(1f, grabbedBody.mass)); } else if ((Object)(object)grabJoint == (Object)null && !grabbedBody.isKinematic) { grabbedBody.AddForce(val * holdStrength, (ForceMode)5); } } private bool BrakeTargetAtSafePoint(Vector3 safePoint, Vector3 aimDirection) { //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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_002e: 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_008c: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_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_00d2: 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_00f3: 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_00f5: 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_0134: 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_0141: 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_016c: 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_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0199: 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_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: 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_021a: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: 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_0238: 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) if ((Object)(object)grabbedBody == (Object)null) { return false; } Vector3 val = ((Component)grabbedBody).transform.TransformPoint(localGrabPoint); Vector3 val2 = safePoint - val; if ((Object)(object)grabbedPawn != (Object)null || (Object)(object)grabbedNpc != (Object)null) { return ((Vector3)(ref val2)).sqrMagnitude <= 0.0625f; } if (grabbedBody.isKinematic) { return ((Vector3)(ref val2)).sqrMagnitude <= 0.0144f; } Vector3 val3 = ((((Vector3)(ref aimDirection)).sqrMagnitude < 0.001f) ? ((Component)this).transform.forward : ((Vector3)(ref aimDirection)).normalized); float num = 0f - Vector3.Dot(val - safePoint, val3); bool num2 = num > 0f; if (num2) { Rigidbody obj = grabbedBody; obj.position += val3 * (num + 0.01f); val = ((Component)grabbedBody).transform.TransformPoint(localGrabPoint); val2 = safePoint - val; } float magnitude = ((Vector3)(ref val2)).magnitude; float num3 = ((state == ControlState.Holding) ? 0.75f : Mathf.Clamp(magnitude * 2.5f, 0.75f, returnSpeed * 0.75f)); Vector3 val4 = Vector3.ClampMagnitude(val2 * 4f, num3); float num4 = Mathf.Lerp(30f, 12f, Mathf.Clamp01(magnitude / 2f)); Vector3 val5 = Vector3.MoveTowards(grabbedBody.linearVelocity, val4, num4 * Time.fixedDeltaTime); float num5 = Vector3.Dot(val5, val3); if (num2 && num5 < 0f) { val5 -= val3 * num5; } else if (magnitude <= 0.35f) { float num6 = Mathf.Max(0.15f, magnitude * 2f); if (num5 < 0f - num6) { val5 += val3 * (0f - num6 - num5); } } grabbedBody.linearVelocity = val5; if (magnitude <= 0.35f) { grabbedBody.angularVelocity = Vector3.MoveTowards(grabbedBody.angularVelocity, Vector3.zero, 12f * Time.fixedDeltaTime); } int num7; if (magnitude <= 0.12f) { Vector3 linearVelocity = grabbedBody.linearVelocity; num7 = ((((Vector3)(ref linearVelocity)).sqrMagnitude <= 0.5625f) ? 1 : 0); if (num7 != 0) { grabbedBody.linearVelocity = Vector3.zero; } } else { num7 = 0; } return (byte)num7 != 0; } private Vector3 GetSafePoint(out Vector3 aimDirection) { //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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_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_006c: 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_0076: 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_0086: 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_0055: 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_00e3: 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_00e9: 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_00f9: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) Pawn val = (((Object)(object)base.Caster == (Object)null) ? null : ((Component)base.Caster).GetComponent()); if ((Object)(object)val != (Object)null) { aimDirection = val.Blackboard.AimDirection; if (aimDirection == Vector3.zero) { aimDirection = ((Component)val).transform.forward; } return val.LookOrigin + ((Vector3)(ref aimDirection)).normalized * GetSafeHoldDistance() + Vector3.up * GetVerticalOffset(); } aimDirection = (((Object)(object)base.Caster == (Object)null) ? ((Component)this).transform.forward : ((Component)base.Caster).transform.forward); return (((Object)(object)base.Caster == (Object)null) ? ((Component)this).transform.position : ((Component)base.Caster).transform.position) + ((Vector3)(ref aimDirection)).normalized * GetSafeHoldDistance() + Vector3.up * GetVerticalOffset(); } private float GetSafeHoldDistance() { float num = (((Object)(object)grabbedNpc != (Object)null) ? enemyHoldDistance : ((!((Object)(object)grabbedPawn != (Object)null)) ? itemHoldDistance : playerHoldDistance)); return Mathf.Max(GetMinimumHoldDistance(), num + holdDistanceAdjustment); } private float GetMinimumHoldDistance() { if ((Object)(object)grabbedNpc != (Object)null) { return 1f; } if ((Object)(object)grabbedPawn != (Object)null) { return 0.5f; } return 0.25f; } private float GetVerticalOffset() { return raisedHeight + ((Time.time < slamUntil) ? (-3f) : 0f); } private string GetTargetKind() { if ((Object)(object)grabbedNpc != (Object)null) { return "enemy"; } if ((Object)(object)grabbedPawn != (Object)null) { return "player"; } return "item"; } private void CreateGrabJoint() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_00ac: 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) if (!((Object)(object)grabbedBody == (Object)null) && !grabbedBody.isKinematic && !((Object)(object)grabJoint != (Object)null)) { Transform val = (((Object)(object)palmTransform == (Object)null) ? ((Component)this).transform : palmTransform); anchorPoint = new GameObject("ControlAnchor"); anchorPoint.transform.SetParent(val, false); Rigidbody val2 = anchorPoint.AddComponent(); val2.isKinematic = true; val2.useGravity = false; grabJoint = ((Component)grabbedBody).gameObject.AddComponent(); ((Joint)grabJoint).connectedBody = val2; ((Joint)grabJoint).anchor = localGrabPoint; ((Joint)grabJoint).connectedAnchor = Vector3.zero; grabJoint.spring = 300f; grabJoint.damper = Mathf.Clamp(2f * Mathf.Sqrt(grabJoint.spring * grabbedBody.mass), 35f, 120f); grabJoint.maxDistance = 0f; ((Joint)grabJoint).autoConfigureConnectedAnchor = false; } } private void SetCasterCollisionIgnored(bool ignore) { if (ignoringCasterCollision == ignore) { return; } if ((Object)(object)casterCapsule == (Object)null && (Object)(object)base.Caster != (Object)null) { Pawn component = ((Component)base.Caster).GetComponent(); casterCapsule = (Collider)(object)(((Object)(object)component == (Object)null) ? null : component.CapsuleCollider); } if ((Object)(object)casterCapsule == (Object)null || grabbedColliders == null) { return; } Collider[] array = grabbedColliders; foreach (Collider val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)casterCapsule) { Physics.IgnoreCollision(casterCapsule, val, ignore); } } ignoringCasterCollision = ignore; } private void DestroyGrabJoint() { if ((Object)(object)grabJoint != (Object)null) { Object.Destroy((Object)(object)grabJoint); grabJoint = null; } if ((Object)(object)anchorPoint != (Object)null) { Object.Destroy((Object)(object)anchorPoint); anchorPoint = null; } } private void SetHandCollidersEnabled(bool enabled) { if (handColliders == null) { return; } Collider[] array = handColliders; foreach (Collider val in array) { if ((Object)(object)val != (Object)null) { val.enabled = enabled; } } } [Server] public void DropAndDestroy() { if (NetworkServer.active && state != ControlState.Ending) { state = ControlState.Ending; DestroyGrabJoint(); ClearTargetReferences(); NetworkServer.Destroy(((Component)this).gameObject); } } [Server] internal void MoveCloser() { if (NetworkServer.active && HasGrabbedTarget) { holdDistanceAdjustment -= 0.5f; state = ControlState.Returning; Plugin.Log.LogDebug((object)$"Control CLOSER: {GetSafeHoldDistance():0.00}m."); } } [Server] internal void Raise() { if (NetworkServer.active && HasGrabbedTarget) { raisedHeight = Mathf.Min(4f, raisedHeight + 1f); state = ControlState.Returning; Plugin.Log.LogDebug((object)$"Control RAISE: vertical offset {raisedHeight:0.00}m."); } } [Server] internal void SlamDown(float force) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active && HasGrabbedTarget) { slamUntil = Time.time + 0.5f; state = ControlState.Returning; ApplyActionImpulse(Vector3.down, force); Plugin.Log.LogDebug((object)"Control SLAM DOWN."); } } [Server] internal void ThrowAndDestroy(float force, ControlDirection controlDirection) { //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_0051: 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_0071: 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_0088: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active && !((Object)(object)grabbedBody == (Object)null)) { Vector3 throwDirection = GetThrowDirection(controlDirection); Rigidbody val = grabbedBody; Pawn val2 = grabbedPawn; NpcBehaviour val3 = grabbedNpc; wasThrown = true; state = ControlState.Ending; DestroyGrabJoint(); if ((Object)(object)val2 != (Object)null) { val2.SvAddExternalImpulse(throwDirection * force); } else if ((Object)(object)val3 != (Object)null) { val3.AddForce(throwDirection * (force * 2f)); } else if (!val.isKinematic) { val.AddForce(throwDirection * force, (ForceMode)2); } ClearTargetReferences(); NetworkServer.Destroy(((Component)this).gameObject); } } private void ApplyActionImpulse(Vector3 direction, float force) { //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_001d: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0074: Unknown result type (might be due to invalid IL or missing references) direction = ((Vector3)(ref direction)).normalized; if ((Object)(object)grabbedPawn != (Object)null) { grabbedPawn.SvAddExternalImpulse(direction * force); } else if ((Object)(object)grabbedNpc != (Object)null) { grabbedNpc.AddForce(direction * (force * 2f)); } else if ((Object)(object)grabbedBody != (Object)null && !grabbedBody.isKinematic) { grabbedBody.AddForce(direction * force, (ForceMode)2); } } private Vector3 GetThrowDirection(ControlDirection direction) { //IL_0003: 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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_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_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_00b9: 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_00c0: 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_00c7: 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_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_00da: 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_00e3: 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_00ee: 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_00f4: 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_00fd: 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) //IL_0103: 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_010b: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0127: 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) //IL_012f: 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_0136: 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) //IL_013c: 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_0145: 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_014b: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: 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_0161: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_016f: 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) GetSafePoint(out var aimDirection); aimDirection = ((aimDirection == Vector3.zero) ? ((Component)this).transform.forward : ((Vector3)(ref aimDirection)).normalized); Vector3 val = Vector3.Cross(Vector3.up, aimDirection); if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = (((Object)(object)base.Caster == (Object)null) ? ((Component)this).transform.right : ((Component)base.Caster).transform.right); } ((Vector3)(ref val)).Normalize(); Vector3 val2; switch (direction) { case ControlDirection.Back: return -aimDirection; case ControlDirection.Left: return -val; case ControlDirection.Right: return val; case ControlDirection.Up: return Vector3.up; case ControlDirection.Down: return Vector3.down; case ControlDirection.UpLeft: val2 = Vector3.up - val; return ((Vector3)(ref val2)).normalized; case ControlDirection.UpRight: val2 = Vector3.up + val; return ((Vector3)(ref val2)).normalized; case ControlDirection.DownLeft: val2 = Vector3.down - val; return ((Vector3)(ref val2)).normalized; case ControlDirection.DownRight: val2 = Vector3.down + val; return ((Vector3)(ref val2)).normalized; case ControlDirection.ForwardLeft: val2 = aimDirection - val; return ((Vector3)(ref val2)).normalized; case ControlDirection.ForwardRight: val2 = aimDirection + val; return ((Vector3)(ref val2)).normalized; case ControlDirection.BackLeft: val2 = -aimDirection - val; return ((Vector3)(ref val2)).normalized; case ControlDirection.BackRight: val2 = -aimDirection + val; return ((Vector3)(ref val2)).normalized; default: return aimDirection; } } private void ClearTargetReferences() { SetCasterCollisionIgnored(ignore: false); grabbedBody = null; grabbedPawn = null; grabbedNpc = null; grabbedColliders = null; casterCapsule = null; npcNavigationDisabled = false; } private void HandleTargetTags(NetworkIdentity targetIdentity) { NpcBehaviour val = default(NpcBehaviour); if ((Object)(object)base.Caster != (Object)null && ((Component)targetIdentity).TryGetComponent(ref val)) { val.OnAggro(base.Caster); } TaggableObject val2 = default(TaggableObject); if (((Component)targetIdentity).TryGetComponent(ref val2)) { val2.AddTag(TagReferences.MovedTag); if ((Object)(object)base.spellTag != (Object)null) { val2.AddTag(base.spellTag); } } ValuableObject val3 = default(ValuableObject); if ((Object)(object)base.Caster != (Object)null && ((Component)targetIdentity).TryGetComponent(ref val3)) { val3.SetAndPropagateRecentInteractor(base.Caster.netId); } } private IEnumerator DestroyAfterDelay() { yield return (object)new WaitForSeconds(1f); if (NetworkServer.active) { NetworkServer.Destroy(((Component)this).gameObject); } } private void InvokeVisualRpc(MethodInfo method) { if ((Object)(object)visualBridge == (Object)null || method == null) { return; } try { method.Invoke(visualBridge, null); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Control hand visual RPC failed (" + method.Name + "): " + ex.GetBaseException().Message)); } } private void OnDestroy() { SetCasterCollisionIgnored(ignore: false); DestroyGrabJoint(); if (!wasThrown && npcNavigationDisabled) { npcNavigationDisabled = false; } } } public sealed class ControlSpell : SpawnableObjectSpell { private bool hasSpawnedHand; private bool holdInputActive; public override bool IsInstantCast => false; internal bool HoldInputActive => holdInputActive; internal void Configure(SpellData data) { ((Spell)this).spellData = data; } public override void OnSpellActivate() { hasSpawnedHand = false; ControlInputRelay component = ((Component)this).GetComponent(); holdInputActive = (Object)(object)component != (Object)null && component.ServerHoldActive; Plugin.Log.LogDebug((object)$"Control activated on server; R held: {holdInputActive}."); base.OnSpellActivate(); } [Server] internal void SetHoldInput(bool active) { if (NetworkServer.active) { holdInputActive = active; } } [Server] protected override void SpawnSingleObject(Vector3 position, Quaternion rotation) { //IL_004f: 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_00b5: 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 (!NetworkServer.active) { Debug.LogWarning((object)"[ControlSpell] Spawn attempted while the server was inactive."); return; } if ((Object)(object)((Spell)this).spellData == (Object)null || (Object)(object)((Spell)this).spellData.objectToSpawnPrefab == (Object)null) { Debug.LogError((object)"[ControlSpell] Runtime SpellData or hand prefab is missing."); ((Spell)this).StopSpell(); return; } GameObject val = Object.Instantiate(((Spell)this).spellData.objectToSpawnPrefab, position, rotation); val.SetActive(true); ControlProjectileHand component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Debug.LogError((object)"[ControlSpell] Spawned prefab has no ControlProjectileHand."); Object.Destroy((Object)(object)val); ((Spell)this).StopSpell(); return; } NetworkServer.Spawn(val, (NetworkConnectionToClient)null); ((BaseProjectile)component).Initialize(((Spell)this).NetworkcasterIdentity, (Spell)(object)this); base.activeSpawnedObjects.Add(component); hasSpawnedHand = true; ((SpawnableObjectSpell)this).OnObjectInitialized(component); ((Spell)this).RpcPlayEffect((SpellEffectType)1, position, rotation); Plugin.Log.LogDebug((object)$"Control hand spawned; R held: {holdInputActive}."); } [Server] internal bool TryApplyAction(ControlActionKind actionKind, ControlDirection direction) { if (!NetworkServer.active || !holdInputActive || (Object)(object)base.activeSpawnedObject == (Object)null || !base.activeSpawnedObject.HasGrabbedTarget) { return false; } ControlProjectileHand activeSpawnedObject = base.activeSpawnedObject; switch (actionKind) { case ControlActionKind.Closer: activeSpawnedObject.MoveCloser(); return false; case ControlActionKind.Raise: activeSpawnedObject.Raise(); return false; case ControlActionKind.SlamDown: activeSpawnedObject.SlamDown(Plugin.ControlThrowForce); return false; case ControlActionKind.Throw: activeSpawnedObject.ThrowAndDestroy(Plugin.ControlThrowForce, direction); base.activeSpawnedObjects.Clear(); ((Spell)this).StopSpell(); return true; default: return false; } } [Server] public override void OnSpellDeactivate() { if (!NetworkServer.active) { Debug.LogWarning((object)"[ControlSpell] Deactivation attempted while the server was inactive."); return; } ((MonoBehaviour)this).StopAllCoroutines(); ControlProjectileHand activeSpawnedObject = base.activeSpawnedObject; if ((Object)(object)activeSpawnedObject != (Object)null) { activeSpawnedObject.DropAndDestroy(); } base.activeSpawnedObjects.Clear(); hasSpawnedHand = false; holdInputActive = false; Plugin.Log.LogDebug((object)"Control deactivated on server."); base.OnSpellDeactivate(); } public override void Update() { ((Spell)this).Update(); if (((NetworkBehaviour)this).isServer && ((Spell)this).isCasting && hasSpawnedHand && (Object)(object)base.activeSpawnedObject == (Object)null) { ((Spell)this).StopSpell(); VoiceSpell component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.NetworkcurrentSpell == (Object)(object)this) { component.NetworkcurrentSpell = null; ((Spell)component).NetworkisCasting = false; component.StopPrimingAnimation(); } } } } public sealed class FireBallProjectile : BaseProjectile { [SerializeField] private GameObject explosionVfxPrefab; [SerializeField] private NetworkIdentity explosionPrefab; [SerializeField] private EventReference explosionSfx; private bool hasExploded; internal void Configure(ProjectileData data, SpellData ownerSpellData, GameObject igniteBoomExplosionVfx, NetworkIdentity igniteBoomExplosionPrefab, EventReference igniteBoomExplosionSfx, float lifetime) { //IL_001e: 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) base.projectileData = data; base.spellData = ownerSpellData; explosionVfxPrefab = igniteBoomExplosionVfx; explosionPrefab = igniteBoomExplosionPrefab; explosionSfx = igniteBoomExplosionSfx; base.ttl = lifetime; base.ignoreCaster = true; base.delayProcessObstacles = true; } protected override void OnTargetHit(Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity) { if (((NetworkBehaviour)this).isServer && !hasExploded) { TriggerIgniteBoomExplosion(); } } protected override void OnWallHit(Collider wall) { if (((NetworkBehaviour)this).isServer && !hasExploded) { TriggerIgniteBoomExplosion(); } ((BaseProjectile)this).OnWallHit(wall); } [Server] private void TriggerIgniteBoomExplosion() { //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_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_00b5: 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_0083: 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_009b: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || hasExploded) { return; } hasExploded = true; Vector3 position = ((Component)this).transform.position; Quaternion rotation = ((Component)this).transform.rotation; if ((Object)(object)explosionVfxPrefab != (Object)null && (Object)(object)VfxManager.Instance != (Object)null) { int vfxId = VfxManager.Instance.GetVfxId(explosionVfxPrefab); if (vfxId != -1) { GameManager.Instance.RpcSpawnVfx(vfxId, position); } } AudioManager val = default(AudioManager); if (!((EventReference)(ref explosionSfx)).IsNull && Service.Get(ref val)) { int eventId = val.GetEventId(explosionSfx); if (eventId != -1) { GameManager.Instance.RpcPlaySfxEvent(eventId, position); } } if ((Object)(object)explosionPrefab != (Object)null) { GameManager.SpawnNetworkPrefab(explosionPrefab, position, rotation, true); } } } public sealed class FireBallSpell : SpawnableObjectSpell { internal void Configure(SpellData data) { ((Spell)this).spellData = data; } [Server] protected override void SpawnSingleObject(Vector3 position, Quaternion rotation) { //IL_0049: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { Debug.LogWarning((object)"[FireBallSpell] Spawn attempted while the server was inactive."); return; } if ((Object)(object)((Spell)this).spellData == (Object)null || (Object)(object)((Spell)this).spellData.objectToSpawnPrefab == (Object)null) { Debug.LogError((object)"[FireBallSpell] Runtime SpellData or projectile prefab is missing."); return; } GameObject val = Object.Instantiate(((Spell)this).spellData.objectToSpawnPrefab, position, rotation); val.SetActive(true); BaseProjectile component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Debug.LogError((object)"[FireBallSpell] Spawned prefab has no BaseProjectile."); Object.Destroy((Object)(object)val); return; } NetworkServer.Spawn(val, (NetworkConnectionToClient)null); component.Initialize(((Spell)this).NetworkcasterIdentity, (Spell)(object)this); base.activeSpawnedObjects.Add(component); ((SpawnableObjectSpell)this).OnObjectInitialized(component); ((Spell)this).RpcPlayEffect((SpellEffectType)1, position, rotation); } } [BepInPlugin("Hero_brian124.Herobrian_spells", "Herobrian_spells", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "Hero_brian124.Herobrian_spells"; public const string PluginName = "Herobrian_spells"; public const string PluginVersion = "1.0.0"; public const string VoiceCommandKey = "MOD_SPELL_FIR_FIRE_BALL"; public const string ControlVoiceCommandKey = "MOD_SPELL_ARC_CONTROL"; public const string VomitVoiceCommandKey = "MOD_SPELL_GRO_VOMIT"; public const string ZawardoVoiceCommandKey = "MOD_SPELL_BAS_ZAWARDO"; internal const uint ProjectileAssetId = 4051612689u; internal const uint ControlHandAssetId = 3229223441u; internal const uint VomitStreamAssetId = 2963347217u; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } internal static string[] PhraseTokens { get; private set; } = new string[2] { "FIRE", "BALL" }; internal static string[] ControlPhraseTokens { get; private set; } = new string[1] { "CONTROL" }; internal static string[] VomitPhraseTokens { get; private set; } = new string[1] { "VOMIT" }; internal static string[] ZawardoPhraseTokens { get; private set; } = new string[2] { "THE", "WORLD" }; internal static float ProjectileSpeed { get; private set; } internal static float ProjectileRange { get; private set; } internal static float ProjectileLifetime { get; private set; } internal static float Cooldown { get; private set; } internal static int Charges { get; private set; } internal static float ChargeRegenSeconds { get; private set; } internal static float ControlHoldStrength { get; private set; } internal static float ControlThrowForce { get; private set; } internal static Key ControlHoldKey { get; private set; } = (Key)32; private void Awake() { //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: 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_02f5: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ConfigEntry val = ((BaseUnityPlugin)this).Config.Bind("Voice", "Phrase", "FIRE BALL", "Words spoken to cast the spell. Restart the game after changing this."); ConfigEntry val2 = ((BaseUnityPlugin)this).Config.Bind("Projectile", "Speed", 15f, "Projectile speed."); ConfigEntry val3 = ((BaseUnityPlugin)this).Config.Bind("Projectile", "Range", 30f, "Maximum travel distance."); ConfigEntry val4 = ((BaseUnityPlugin)this).Config.Bind("Projectile", "Lifetime", 5f, "Maximum projectile lifetime."); ConfigEntry val5 = ((BaseUnityPlugin)this).Config.Bind("Spell", "Cooldown", 1f, "Cooldown after casting."); ConfigEntry val6 = ((BaseUnityPlugin)this).Config.Bind("Spell", "Charges", 3, "Maximum charges."); ConfigEntry val7 = ((BaseUnityPlugin)this).Config.Bind("Spell", "ChargeRegenSeconds", 8f, "Seconds to regenerate one charge."); ConfigEntry obj = ((BaseUnityPlugin)this).Config.Bind("Control Voice", "ControlPhrase", "CONTROL", "Words spoken to start Control. Restart after changing this."); ConfigEntry val8 = ((BaseUnityPlugin)this).Config.Bind("Vomit Voice", "VomitPhrase", "VOMIT", "Words spoken to cast Vomit Spell. Restart after changing this."); ConfigEntry val9 = ((BaseUnityPlugin)this).Config.Bind("The World Voice", "TheWorldPhrase", "THE WORLD", "Words spoken to cast The World. Restart after changing this."); ConfigEntry val10 = ((BaseUnityPlugin)this).Config.Bind("Control", "HoldStrength", 8f, "Correction strength used to keep players, NPCs, and props held."); ConfigEntry val11 = ((BaseUnityPlugin)this).Config.Bind("Control", "ThrowForce", 30f, "Force applied when the caster says THROW."); ConfigEntry val12 = ((BaseUnityPlugin)this).Config.Bind("Control", "HoldKey", (Key)32, "Keyboard key held to keep the Control hand attached."); PhraseTokens = NormalizePhrase(val.Value); ControlPhraseTokens = NormalizePhrase(obj.Value, "CONTROL"); VomitPhraseTokens = NormalizePhrase(val8.Value, "VOMIT"); ZawardoPhraseTokens = NormalizePhrase(val9.Value, "THE", "WORLD"); ProjectileSpeed = Math.Max(1f, val2.Value); ProjectileRange = Math.Max(1f, val3.Value); ProjectileLifetime = Math.Max(0.5f, val4.Value); Cooldown = Math.Max(0f, val5.Value); Charges = Math.Max(1, val6.Value); ChargeRegenSeconds = Math.Max(0.1f, val7.Value); ControlHoldStrength = Math.Max(1f, val10.Value); ControlThrowForce = Math.Max(1f, val11.Value); ControlHoldKey = (Key)(((int)val12.Value == 0) ? 32 : ((int)val12.Value)); _harmony = new Harmony("Hero_brian124.Herobrian_spells"); _harmony.PatchAll(typeof(Plugin).Assembly); ((Component)this).gameObject.AddComponent(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded Herobrian_spells 1.0.0; Fire Ball: " + string.Join(" ", PhraseTokens) + "; Control: " + string.Join(" ", ControlPhraseTokens) + "; Vomit Spell: " + string.Join(" ", VomitPhraseTokens) + "; The World: " + string.Join(" ", ZawardoPhraseTokens) + "; " + $"{ControlActionCatalog.VoiceActions.Length} Control voice actions")); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private static string[] NormalizePhrase(string phrase, params string[] fallback) { string[] array = (from token in (phrase ?? string.Empty).Split(new char[3] { ' ', '-', '\t' }, StringSplitOptions.RemoveEmptyEntries) select token.Trim().ToUpperInvariant() into token where token.Length > 0 select token).ToArray(); if (array.Length == 0) { if (fallback.Length != 0) { return fallback; } return new string[2] { "FIRE", "BALL" }; } return array; } internal static IEnumerable> GetVoiceCommands() { yield return new KeyValuePair("MOD_SPELL_FIR_FIRE_BALL", PhraseTokens); yield return new KeyValuePair("MOD_SPELL_ARC_CONTROL", ControlPhraseTokens); yield return new KeyValuePair("MOD_SPELL_GRO_VOMIT", VomitPhraseTokens); yield return new KeyValuePair("MOD_SPELL_BAS_ZAWARDO", ZawardoPhraseTokens); foreach (KeyValuePair voiceCommand in ControlActionCatalog.GetVoiceCommands()) { yield return voiceCommand; } } internal static bool TryGetVoiceCommand(string key, out string[] tokens) { foreach (KeyValuePair voiceCommand in GetVoiceCommands()) { if (string.Equals(key, voiceCommand.Key, StringComparison.Ordinal)) { tokens = voiceCommand.Value; return true; } } tokens = null; return false; } } internal static class FireBallBootstrap { private static readonly FieldInfo VoiceSpellsField = AccessTools.Field(typeof(VoiceSpell), "spells"); private static readonly FieldInfo MinePrefabField = AccessTools.Field(typeof(MineSpell), "minePrefab"); private static readonly FieldInfo MineSpawnSfxField = AccessTools.Field(typeof(MineTrigger), "spawnSfx"); private static readonly FieldInfo MineExplosionSfxField = AccessTools.Field(typeof(MineTrigger), "explosionSfx"); private static readonly FieldInfo NetworkAssetIdField = AccessTools.Field(typeof(NetworkIdentity), "_assetId"); private static readonly FieldInfo NetworkHasSpawnedField = AccessTools.Field(typeof(NetworkIdentity), "hasSpawned"); private static GameObject _networkProjectilePrefab; private static SpellData _spellData; private static ProjectileData _projectileData; private static EventReference _igniteBoomSpawnSfx; private static EventReference _igniteBoomExplosionSfx; internal static void Install(YapNetworkManager manager) { if ((Object)(object)manager == (Object)null) { return; } GameObject val = FindPrefab(manager, "PropWandOfFire"); GameObject val2 = FindPrefab(manager, "Fireball"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)"Fire Ball was not installed: PropWandOfFire or Fireball was not found in YapNetworkManager.spawnPrefabs."); return; } NetworkIdentity val3 = default(NetworkIdentity); if (((NetworkManager)manager).spawnPrefabs.Any((GameObject prefab) => (Object)(object)prefab != (Object)null && prefab.TryGetComponent(ref val3) && val3.assetId == 4051612689u)) { Plugin.Log.LogError((object)$"Fire Ball asset ID collision: {4051612689u}. The mod will not install."); return; } VoiceSpell component = val.GetComponent(); LaunchSelfSpell component2 = val.GetComponent(); MineSpell component3 = val.GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { Plugin.Log.LogError((object)"Fire Ball was not installed: the Fire Wand is missing VoiceSpell, LaunchSelfSpell, or MineSpell."); return; } EnsureRuntimeData(manager, component2, component3); EnsureProjectilePrefab(val2, component3); EnsureSpellOnWand(val, component); } private static GameObject FindPrefab(YapNetworkManager manager, string name) { return ((IEnumerable)((NetworkManager)manager).spawnPrefabs).FirstOrDefault((Func)((GameObject prefab) => (Object)(object)prefab != (Object)null && string.Equals(((Object)prefab).name, name, StringComparison.Ordinal))); } private static void EnsureRuntimeData(YapNetworkManager manager, LaunchSelfSpell launchSelfSpell, MineSpell mineSpell) { //IL_00b6: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) ReadIgniteBoomAudio(mineSpell); if ((Object)(object)_spellData == (Object)null) { _spellData = Object.Instantiate(((Spell)launchSelfSpell).SpellData); ((Object)_spellData).name = "SD_FIR_FIRE_BALL_MOD"; _spellData.spellName = "FIRE BALL"; _spellData.voiceCommandKey = "MOD_SPELL_FIR_FIRE_BALL"; _spellData.cooldown = Plugin.Cooldown; _spellData.charges = Plugin.Charges; _spellData.chargePerCast = 1; _spellData.chargeCostPerSecondCast = 0; _spellData.chargeRegenInterval = Plugin.ChargeRegenSeconds; _spellData.chargesRegenPerInterval = 1; _spellData.chargeRegenDelay = 0.5f; _spellData.spawnLocation = (SpawnLocation)1; _spellData.spawnOffset = Vector3.zero; _spellData.applyLookTransform = true; _spellData.spawnDelay = 0.1f; _spellData.castEvent = _igniteBoomSpawnSfx; _spellData.impactEvent = default(EventReference); _spellData.impactVFXPrefab = null; } if (!((Object)(object)_projectileData == (Object)null)) { return; } BaseProjectile val = (from prefab in ((NetworkManager)manager).spawnPrefabs where (Object)(object)prefab != (Object)null select prefab.GetComponent()).FirstOrDefault((Func)((BaseProjectile projectile) => (Object)(object)projectile != (Object)null && (Object)(object)projectile.ProjectileData != (Object)null && projectile is ProjectileTornado)); if ((Object)(object)val == (Object)null) { val = (from prefab in ((NetworkManager)manager).spawnPrefabs where (Object)(object)prefab != (Object)null select prefab.GetComponent()).FirstOrDefault((Func)((BaseProjectile projectile) => (Object)(object)projectile != (Object)null && (Object)(object)projectile.ProjectileData != (Object)null && ((LayerMask)(ref projectile.ProjectileData.wallLayer)).value != 0)); } if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("No vanilla projectile with a wall collision profile was found."); } _projectileData = Object.Instantiate(val.ProjectileData); ((Object)_projectileData).name = "PD_FIR_FIRE_BALL_MOD"; _projectileData.speed = Plugin.ProjectileSpeed; _projectileData.gravity = 0f; _projectileData.maxTravelDistance = Plugin.ProjectileRange; _projectileData.spawnInvulnerability = 0.15f; _projectileData.enablePiercing = false; _projectileData.maxPierceCount = 0; _projectileData.projectileCount = 1; _projectileData.maxProjectileCount = 0; _projectileData.spreadAngle = 0f; _projectileData.useRandomSpread = false; _projectileData.verticalDegreeRandomness = 0f; _projectileData.projectileFireDelay = 0f; _projectileData.chanceForMultiShot = 0f; } private static void ReadIgniteBoomAudio(MineSpell mineSpell) { //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_0058: 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) object? value = MinePrefabField.GetValue(mineSpell); NetworkIdentity val = (NetworkIdentity)((value is NetworkIdentity) ? value : null); MineTrigger val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent()); if ((Object)(object)val2 == (Object)null) { throw new InvalidOperationException("Ignite Boom's mine prefab or MineTrigger could not be resolved."); } _igniteBoomSpawnSfx = (EventReference)MineSpawnSfxField.GetValue(val2); _igniteBoomExplosionSfx = (EventReference)MineExplosionSfxField.GetValue(val2); if (((EventReference)(ref _igniteBoomSpawnSfx)).IsNull || ((EventReference)(ref _igniteBoomExplosionSfx)).IsNull) { throw new InvalidOperationException("Ignite Boom's spawn or explosion FMOD event is empty."); } } private static void EnsureProjectilePrefab(GameObject vanillaFireballPrefab, MineSpell mineSpell) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_networkProjectilePrefab != (Object)null) { _spellData.objectToSpawnPrefab = _networkProjectilePrefab; return; } bool activeSelf = vanillaFireballPrefab.activeSelf; try { vanillaFireballPrefab.SetActive(false); _networkProjectilePrefab = Object.Instantiate(vanillaFireballPrefab); } finally { vanillaFireballPrefab.SetActive(activeSelf); } ((Object)_networkProjectilePrefab).name = "FireBallModProjectile"; _networkProjectilePrefab.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_networkProjectilePrefab); NetworkIdentity component = _networkProjectilePrefab.GetComponent(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("The cloned Fireball prefab has no NetworkIdentity."); } NetworkAssetIdField.SetValue(component, 4051612689u); NetworkHasSpawnedField.SetValue(component, false); component.sceneId = 0uL; NetworkBehaviour[] components = _networkProjectilePrefab.GetComponents(); foreach (NetworkBehaviour val in components) { if (((object)val).GetType().Name.IndexOf("NetworkTransform", StringComparison.Ordinal) >= 0) { val.syncDirection = (SyncDirection)0; } } Rigidbody[] componentsInChildren = _networkProjectilePrefab.GetComponentsInChildren(true); foreach (Rigidbody obj in componentsInChildren) { obj.useGravity = false; obj.isKinematic = true; obj.detectCollisions = true; } Collider[] componentsInChildren2 = _networkProjectilePrefab.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].isTrigger = true; } DisableIfPresent(_networkProjectilePrefab); DisableIfPresent(_networkProjectilePrefab); DisableIfPresent(_networkProjectilePrefab); (_networkProjectilePrefab.GetComponent() ?? _networkProjectilePrefab.AddComponent()).Configure(_projectileData, _spellData, mineSpell.ExplosionVfxPrefab, mineSpell.ExplosionPrefab, _igniteBoomExplosionSfx, Plugin.ProjectileLifetime); _spellData.objectToSpawnPrefab = _networkProjectilePrefab; Plugin.Log.LogInfo((object)$"Prepared Fire Ball projectile prefab with asset ID {4051612689u}."); } private static void DisableIfPresent(GameObject gameObject) where T : Behaviour { T component = gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } } private static void EnsureSpellOnWand(GameObject fireWandPrefab, VoiceSpell voiceSpell) { FireBallSpell fireBallSpell = fireWandPrefab.GetComponent() ?? fireWandPrefab.AddComponent(); fireBallSpell.Configure(_spellData); ((Behaviour)fireBallSpell).enabled = true; Spell[] array = (VoiceSpellsField.GetValue(voiceSpell) as Spell[]) ?? Array.Empty(); if (!array.Contains((Spell)(object)fireBallSpell)) { VoiceSpellsField.SetValue(voiceSpell, array.Concat((IEnumerable)(object)new Spell[1] { (Spell)fireBallSpell }).ToArray()); Plugin.Log.LogInfo((object)$"Added Fire Ball to PropWandOfFire ({array.Length + 1} total spell entries)."); } } internal static void RegisterClientSpawnHandler() { //IL_0033: 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_0049: Expected O, but got Unknown //IL_0049: Expected O, but got Unknown if ((Object)(object)_networkProjectilePrefab == (Object)null) { Plugin.Log.LogWarning((object)"Cannot register Fire Ball client spawn handler: prefab is not prepared."); return; } NetworkClient.UnregisterSpawnHandler(4051612689u); NetworkClient.RegisterSpawnHandler(4051612689u, new SpawnHandlerDelegate(SpawnClientProjectile), new UnSpawnDelegate(UnspawnClientProjectile)); Plugin.Log.LogInfo((object)$"Registered Fire Ball client spawn handler for asset ID {4051612689u}."); } private static GameObject SpawnClientProjectile(SpawnMessage message) { //IL_0005: 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) GameObject obj = Object.Instantiate(_networkProjectilePrefab, message.position, message.rotation); obj.SetActive(true); return obj; } private static void UnspawnClientProjectile(GameObject instance) { if ((Object)(object)instance != (Object)null) { Object.Destroy((Object)(object)instance); } } } [HarmonyPatch(typeof(YapNetworkManager), "Initialise")] internal static class NetworkManagerInitialisePatch { [HarmonyPrefix] private static void Prefix(YapNetworkManager __instance) { try { FireBallBootstrap.Install(__instance); ControlBootstrap.Install(__instance); VomitBootstrap.Install(__instance); ZawardoBootstrap.Install(__instance); } catch (Exception arg) { Plugin.Log.LogError((object)$"Spell expansion installation failed: {arg}"); } } } [HarmonyPatch(typeof(YapNetworkManager), "OnStartClient")] internal static class NetworkManagerStartClientPatch { [HarmonyPostfix] private static void Postfix() { try { FireBallBootstrap.RegisterClientSpawnHandler(); ControlBootstrap.RegisterClientSpawnHandler(); VomitBootstrap.RegisterClientSpawnHandler(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Spell expansion client registration failed: {arg}"); } } } [HarmonyPatch(typeof(VoiceManager), "LoadLocalisationData")] internal static class VoiceLocalisationLoadPatch { [HarmonyPostfix] private static void Postfix(VoiceManager __instance) { VoicePhraseRegistration.AddToAllTranslators(__instance); } } [HarmonyPatch(typeof(VoiceManager), "SetLanguage")] internal static class VoiceLanguagePatch { [HarmonyPrefix] private static void Prefix(VoiceManager __instance) { VoicePhraseRegistration.AddToCurrentTranslator(__instance); } } [HarmonyPatch(typeof(VoiceManager), "TryGetVoiceCommand")] internal static class VoiceCommandLookupPatch { [HarmonyPrefix] private static bool Prefix(string key, ref string[] command, ref bool __result) { if (!Plugin.TryGetVoiceCommand(key, out var tokens)) { return true; } command = tokens; __result = true; return false; } } internal static class VoicePhraseRegistration { private static readonly FieldInfo TranslatorsField = AccessTools.Field(typeof(VoiceManager), "_voskTranslators"); private static readonly FieldInfo CurrentTranslatorField = AccessTools.Field(typeof(VoiceManager), "_currentVoskTranslator"); internal static void AddToAllTranslators(VoiceManager manager) { try { if (!(TranslatorsField.GetValue(manager) is IEnumerable enumerable)) { return; } foreach (object item in enumerable) { AddToTranslator(item); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not extend all Vosk translators: " + ex.Message)); } } internal static void AddToCurrentTranslator(VoiceManager manager) { try { AddToTranslator(CurrentTranslatorField.GetValue(manager)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not extend the current Vosk translator: " + ex.Message)); } } private static void AddToTranslator(object translator) { if (translator == null) { return; } Type type = translator.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "_commands"); FieldInfo fieldInfo2 = AccessTools.Field(type, "_grammar"); if (fieldInfo.GetValue(translator) is Dictionary dictionary) { foreach (KeyValuePair voiceCommand in Plugin.GetVoiceCommands()) { dictionary[voiceCommand.Key] = voiceCommand.Value; } } string[] value = ((fieldInfo2.GetValue(translator) as string[]) ?? Array.Empty()).Concat(Plugin.GetVoiceCommands().SelectMany((KeyValuePair command) => command.Value)).Distinct(StringComparer.Ordinal).ToArray(); fieldInfo2.SetValue(translator, value); } } internal static class VomitBootstrap { private const float VisualScale = 1.2f; private static readonly FieldInfo VoiceSpellsField = AccessTools.Field(typeof(VoiceSpell), "spells"); private static readonly FieldInfo ControllerSpellDataField = AccessTools.Field(typeof(BaseChanneledController), "spellData"); private static readonly FieldInfo ControllerDataField = AccessTools.Field(typeof(BaseChanneledController), "controllerData"); private static readonly FieldInfo NetworkAssetIdField = AccessTools.Field(typeof(NetworkIdentity), "_assetId"); private static readonly FieldInfo NetworkHasSpawnedField = AccessTools.Field(typeof(NetworkIdentity), "hasSpawned"); private static readonly FieldInfo StreamSizeMultiplierField = AccessTools.Field(typeof(ChanneledStreamView), "sizeMultiplier"); private static readonly FieldInfo StreamViewField = AccessTools.Field(typeof(ChanneledStream), "streamVFX"); private static GameObject networkVomitPrefab; private static SpellData vomitSpellData; internal static void Install(YapNetworkManager manager) { if ((Object)(object)manager == (Object)null) { return; } GameObject val = FindPrefab(manager, "PropWandOfGrotesque"); GameObject val2 = FindPrefab(manager, "PropWandOfFire"); GameObject val3 = FindPrefab(manager, "ChanneledStream"); GameObject val4 = FindPrefab(manager, "ChanneledStream_Lava"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null) { Plugin.Log.LogError((object)"Vomit Spell was not installed: Grotesque, Fire Wand, Grotesque stream, or Ignited Tongue stream was not found."); return; } NetworkIdentity val6 = default(NetworkIdentity); if (((NetworkManager)manager).spawnPrefabs.Any((GameObject prefab) => (Object)(object)prefab != (Object)null && prefab.TryGetComponent(ref val6) && val6.assetId == 2963347217u)) { Plugin.Log.LogError((object)$"Vomit stream asset ID collision: {2963347217u}. Vomit Spell will not install."); return; } VoiceSpell component = val.GetComponent(); PissSpell val5 = ((IEnumerable)val.GetComponents()).FirstOrDefault((Func)((PissSpell spell) => (Object)(object)((Spell)spell).SpellData != (Object)null && string.Equals(((Spell)spell).SpellData.spellName, "PISS-YUK", StringComparison.Ordinal))); LavaSpell component2 = val2.GetComponent(); LavaStream component3 = val4.GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { Plugin.Log.LogError((object)"Vomit Spell was not installed: VoiceSpell, Piss Yuk, Ignited Tongue, or its LavaStream is missing."); return; } EnsureRuntimeData(component2, val5); EnsureVomitPrefab(val3, component3); EnsureSpellOnWand(val, component); } private static GameObject FindPrefab(YapNetworkManager manager, string name) { return ((IEnumerable)((NetworkManager)manager).spawnPrefabs).FirstOrDefault((Func)((GameObject prefab) => (Object)(object)prefab != (Object)null && string.Equals(((Object)prefab).name, name, StringComparison.Ordinal))); } private static void EnsureRuntimeData(LavaSpell ignitedTongue, PissSpell pissYuk) { //IL_0056: 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_006b: 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_0080: 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_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_00aa: 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_00bf: 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_00d4: 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) if (!((Object)(object)vomitSpellData != (Object)null)) { vomitSpellData = Object.Instantiate(((Spell)ignitedTongue).SpellData); ((Object)vomitSpellData).name = "SD_GRO_VOMIT_MOD"; vomitSpellData.spellName = "VOMIT SPELL"; vomitSpellData.voiceCommandKey = "MOD_SPELL_GRO_VOMIT"; vomitSpellData.idleColor = ((Spell)pissYuk).SpellData.idleColor; vomitSpellData.cooldownColor = ((Spell)pissYuk).SpellData.cooldownColor; vomitSpellData.chargeColor = ((Spell)pissYuk).SpellData.chargeColor; vomitSpellData.startEvent = ((Spell)pissYuk).SpellData.startEvent; vomitSpellData.loopEvent = ((Spell)pissYuk).SpellData.loopEvent; vomitSpellData.endEvent = ((Spell)pissYuk).SpellData.endEvent; vomitSpellData.impactEvent = ((Spell)pissYuk).SpellData.impactEvent; Plugin.Log.LogInfo((object)("Prepared Vomit Spell data from Ignited Tongue: " + $"{vomitSpellData.charges} charges, {vomitSpellData.cooldown:0.##}s cooldown, " + "Piss Yuk stream audio and combo interactions.")); } } private static void EnsureVomitPrefab(GameObject grotesqueStreamPrefab, LavaStream vanillaLavaStream) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)networkVomitPrefab != (Object)null) { vomitSpellData.objectToSpawnPrefab = networkVomitPrefab; return; } bool activeSelf = grotesqueStreamPrefab.activeSelf; try { grotesqueStreamPrefab.SetActive(false); networkVomitPrefab = Object.Instantiate(grotesqueStreamPrefab); } finally { grotesqueStreamPrefab.SetActive(activeSelf); } ((Object)networkVomitPrefab).name = "ChanneledStream_VomitMod"; networkVomitPrefab.SetActive(false); Object.DontDestroyOnLoad((Object)(object)networkVomitPrefab); NetworkIdentity component = networkVomitPrefab.GetComponent(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("The cloned lava stream has no NetworkIdentity."); } NetworkAssetIdField.SetValue(component, 2963347217u); NetworkHasSpawnedField.SetValue(component, false); component.sceneId = 0uL; NetworkBehaviour[] components = networkVomitPrefab.GetComponents(); foreach (NetworkBehaviour val in components) { if (((object)val).GetType().Name.IndexOf("NetworkTransform", StringComparison.Ordinal) >= 0) { val.syncDirection = (SyncDirection)0; } } ChanneledStream component2 = networkVomitPrefab.GetComponent(); ChanneledStreamView component3 = networkVomitPrefab.GetComponent(); if ((Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { throw new InvalidOperationException("The cloned Grotesque stream is missing ChanneledStream or ChanneledStreamView."); } ControllerDataField.SetValue(component2, ControllerDataField.GetValue(vanillaLavaStream)); ControllerSpellDataField.SetValue(component2, vomitSpellData); StreamSizeMultiplierField.SetValue(component3, 1.2f); ApplyVomitVisuals(networkVomitPrefab); networkVomitPrefab.AddComponent(); vomitSpellData.objectToSpawnPrefab = networkVomitPrefab; Plugin.Log.LogInfo((object)("Prepared non-fire Grotesque-colored Vomit stream with asset ID " + $"{2963347217u} and {1.2f:0.0}x visual size.")); } private static void ApplyVomitVisuals(GameObject prefab) { //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) ParticleSystem[] componentsInChildren = prefab.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { MainModule main = componentsInChildren[i].main; ((MainModule)(ref main)).startSizeMultiplier = ((MainModule)(ref main)).startSizeMultiplier * 1.2f; } Dictionary vomitMaterials = new Dictionary(); Renderer[] componentsInChildren2 = prefab.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren2) { Material[] sharedMaterials = val.sharedMaterials; Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int j = 0; j < sharedMaterials.Length; j++) { array[j] = GetVomitMaterial(sharedMaterials[j], vomitMaterials); } val.sharedMaterials = array; } LineRenderer3DV2[] componentsInChildren3 = prefab.GetComponentsInChildren(true); foreach (LineRenderer3DV2 val2 in componentsInChildren3) { val2.material = GetVomitMaterial(val2.material, vomitMaterials); if ((Object)(object)val2.meshRenderer != (Object)null) { ((Renderer)val2.meshRenderer).sharedMaterial = val2.material; } } } private static Material GetVomitMaterial(Material source, Dictionary vomitMaterials) { //IL_004f: 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_0097: 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) if ((Object)(object)source == (Object)null) { return null; } if (vomitMaterials.TryGetValue(source, out var value)) { return value; } Material val = Object.Instantiate(source); ((Object)val).name = ((Object)source).name + "_VomitMod"; SetColorIfPresent(val, "_Color", new Color(0.65f, 0.76f, 0.2f, 1f)); SetColorIfPresent(val, "_ColorFront", new Color(0.86f, 0.96f, 0.16f, 1f)); SetColorIfPresent(val, "_ColorBack", new Color(0.16f, 0.24f, 0.035f, 1f)); SetColorIfPresent(val, "_SpecColor", new Color(0.82f, 0.88f, 0.36f, 1f)); vomitMaterials.Add(source, val); return val; } private static void SetColorIfPresent(Material material, string property, Color color) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty(property)) { material.SetColor(property, color); } } private static void EnsureSpellOnWand(GameObject grotesqueWand, VoiceSpell voiceSpell) { VomitSpell vomitSpell = grotesqueWand.GetComponent(); if ((Object)(object)vomitSpell == (Object)null) { vomitSpell = grotesqueWand.AddComponent(); } vomitSpell.Configure(vomitSpellData); ((Behaviour)vomitSpell).enabled = true; Spell[] array = (VoiceSpellsField.GetValue(voiceSpell) as Spell[]) ?? Array.Empty(); if (!array.Contains((Spell)(object)vomitSpell)) { VoiceSpellsField.SetValue(voiceSpell, array.Concat((IEnumerable)(object)new Spell[1] { (Spell)vomitSpell }).ToArray()); Plugin.Log.LogInfo((object)("Added Vomit Spell to PropWandOfGrotesque " + $"({array.Length + 1} total spell entries).")); } } internal static void RegisterClientSpawnHandler() { //IL_0033: 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_0049: Expected O, but got Unknown //IL_0049: Expected O, but got Unknown if ((Object)(object)networkVomitPrefab == (Object)null) { Plugin.Log.LogWarning((object)"Cannot register Vomit Spell client spawn handler: prefab is not prepared."); return; } NetworkClient.UnregisterSpawnHandler(2963347217u); NetworkClient.RegisterSpawnHandler(2963347217u, new SpawnHandlerDelegate(SpawnClientStream), new UnSpawnDelegate(UnspawnClientStream)); Plugin.Log.LogInfo((object)("Registered Vomit Spell client spawn handler for asset ID " + $"{2963347217u}.")); } private static GameObject SpawnClientStream(SpawnMessage message) { //IL_0005: 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) GameObject obj = Object.Instantiate(networkVomitPrefab, message.position, message.rotation); obj.SetActive(true); return obj; } private static void UnspawnClientStream(GameObject instance) { if ((Object)(object)instance != (Object)null) { Object.Destroy((Object)(object)instance); } } internal static ChanneledStreamView GetStreamView(ChanneledStream stream) { if (!((Object)(object)stream == (Object)null)) { object? value = StreamViewField.GetValue(stream); return (ChanneledStreamView)((value is ChanneledStreamView) ? value : null); } return null; } } internal sealed class VomitDamageTracker : MonoBehaviour { private readonly Dictionary npcNextDamageTime = new Dictionary(); internal bool CanDamage(NpcBehaviour npc) { if ((Object)(object)npc == (Object)null) { return false; } if (npcNextDamageTime.TryGetValue(npc, out var value) && Time.time < value) { return false; } npcNextDamageTime[npc] = Time.time + 1f; return true; } } [HarmonyPatch(typeof(ChanneledStream), "OnStreamHit")] internal static class VomitStreamDamagePatch { [HarmonyPostfix] private static void Postfix(ChanneledStream __instance, Collider hitCollider, Vector3 hitDirection, bool __result) { //IL_0056: 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_00e7: 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_00b3: 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_00f9: 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) VomitDamageTracker vomitDamageTracker = default(VomitDamageTracker); if (!__result || !NetworkServer.active || (Object)(object)__instance == (Object)null || (Object)(object)hitCollider == (Object)null || !((Component)__instance).TryGetComponent(ref vomitDamageTracker)) { return; } Transform root = ((Component)hitCollider).transform.root; Pawn val = default(Pawn); NpcBehaviour val3 = default(NpcBehaviour); if (((Component)root).TryGetComponent(ref val)) { if (!((Object)(object)((NetworkBehaviour)val).netIdentity == (Object)(object)((BaseChanneledController)__instance).Networkcaster)) { HitInfo val2 = new HitInfo { damage = 10, ownerNetId = ((!((Object)(object)((BaseChanneledController)__instance).Networkcaster == (Object)null)) ? ((BaseChanneledController)__instance).Networkcaster.netId : 0u), isDirectional = true, impactForce = 0f, sourceTransform = ((Component)__instance).transform, forceRagdoll = false }; val.Hurtbox.OnHitboxHit(val2); } } else if (((Component)root).TryGetComponent(ref val3) && vomitDamageTracker.CanDamage(val3)) { Vector3 val4 = ((((Vector3)(ref hitDirection)).sqrMagnitude < 0.001f) ? ((Component)__instance).transform.forward : ((Vector3)(ref hitDirection)).normalized); val3.OnHit(9, val4, false, ((NetworkBehaviour)__instance).netIdentity); } } } [HarmonyPatch(typeof(ChanneledStream), "RpcOnControllerActivated")] internal static class VomitStreamActivationPatch { [HarmonyPrefix] private static bool Prefix(ChanneledStream __instance) { VomitDamageTracker vomitDamageTracker = default(VomitDamageTracker); if ((Object)(object)__instance == (Object)null || !((Component)__instance).TryGetComponent(ref vomitDamageTracker)) { return true; } if (((NetworkBehaviour)__instance).isServer) { __instance.NetworkisEmitting = false; } ChanneledStreamView streamView = VomitBootstrap.GetStreamView(__instance); if ((Object)(object)streamView != (Object)null) { streamView.SetEmitting(false); streamView.HideMesh(); } return false; } } [HarmonyPatch(typeof(ChanneledStream), "Update")] internal static class VomitStreamVoicePatch { private const float VoiceSensitivity = 0.4f; private const float MinimumVoiceThreshold = 0.1f; [HarmonyPostfix] private static void Postfix(ChanneledStream __instance) { VomitDamageTracker vomitDamageTracker = default(VomitDamageTracker); if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).isServer && !((Object)(object)((BaseChanneledController)__instance).casterPawn == (Object)null) && ((Component)__instance).TryGetComponent(ref vomitDamageTracker)) { bool flag = Mathf.Min(((BaseChanneledController)__instance).casterPawn.VoiceDSP.Volume, 0.4f) / 0.4f >= 0.1f; if (__instance.IsEmitting != flag) { __instance.NetworkisEmitting = flag; } } } } [HarmonyPatch(typeof(ChanneledStream), "OnIsEmittingChanged")] internal static class VomitStreamMeshPatch { [HarmonyPostfix] private static void Postfix(ChanneledStream __instance, bool newState) { VomitDamageTracker vomitDamageTracker = default(VomitDamageTracker); if ((Object)(object)__instance == (Object)null || !((Component)__instance).TryGetComponent(ref vomitDamageTracker)) { return; } ChanneledStreamView streamView = VomitBootstrap.GetStreamView(__instance); if (!((Object)(object)streamView == (Object)null)) { if (newState) { streamView.ShowMesh(); } else { streamView.HideMesh(); } } } } public sealed class VomitSpell : SpawnableObjectSpell { private const float SpellDuration = 10f; private float activationTime = -1f; private bool durationComplete; public override bool IsInstantCast => false; internal void Configure(SpellData data) { ((Spell)this).spellData = data; } public override bool CanCast() { if (((Spell)this).isCasting) { return true; } if (((Spell)this).IsOnCooldown || !((Spell)this).isInitialized || (Object)(object)((Spell)this).NetworkcasterIdentity == (Object)null) { return false; } if (!((Spell)this).HasInfiniteCharges) { if (((Spell)this).currentCharges < ((Spell)this).spellData.chargePerCast) { return false; } if (((Spell)this).spellData.chargeCostPerSecondCast > 0 && ((Spell)this).currentCharges < ((Spell)this).spellData.chargeCostPerSecondCast) { return false; } } return true; } [Server] public override void CastSpell() { if (!NetworkServer.active) { Debug.LogWarning((object)"[VomitSpell] Cast attempted while the server was inactive."); } else if (((Spell)this).isCasting) { ((Spell)this).OnSpellDeactivate(); } else if (((Spell)this).CanCast()) { ((Spell)this).OnSpellActivate(); } } public override void OnSpellActivate() { base.OnSpellActivate(); activationTime = Time.time; durationComplete = false; } public override void Update() { ((Spell)this).Update(); if (((NetworkBehaviour)this).isServer && ((Spell)this).isCasting && !durationComplete && Time.time - activationTime >= 10f) { durationComplete = true; ((Spell)this).OnSpellDeactivate(); } } } internal static class ZawardoBootstrap { private static readonly FieldInfo VoiceSpellsField = AccessTools.Field(typeof(VoiceSpell), "spells"); private static readonly FieldInfo AntiGravityVfxField = AccessTools.Field(typeof(AntiGravitySpell), "antiGravVFX"); private static readonly FieldInfo AntiGravitySfxField = AccessTools.Field(typeof(AntiGravitySpell), "antiGravSfx"); private static readonly FieldInfo ProtectionStatusField = AccessTools.Field(typeof(ProtectionSpell), "protectionStatus"); private static readonly FieldInfo StartCircleVfxField = AccessTools.Field(typeof(TeleportDungeonCircle), "circleActivatingLoopObj"); private static SpellData zawardoSpellData; private static GameObject antiGravityVfx; private static GameObject areaVfx; private static GameObject custodiaVfx; private static float areaVfxScale = 14f; internal static void Install(YapNetworkManager manager) { if ((Object)(object)manager == (Object)null) { return; } GameObject val = FindPrefab(manager, "PropWandOfBasics"); GameObject val2 = FindPrefab(manager, "PropWandOfTelekinesis"); GameObject val3 = FindPrefab(manager, "PropWandOfBlessed"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)"Zawardo was not installed: Wand of Winds or the native Anti-Gravity wand was not found."); return; } VoiceSpell component = val.GetComponent(); Spell val4 = ((IEnumerable)val.GetComponents()).FirstOrDefault((Func)((Spell spell) => !(spell is VoiceSpell) && (Object)(object)spell.SpellData != (Object)null && string.Equals(spell.SpellData.spellName, "VENTO", StringComparison.OrdinalIgnoreCase))); AntiGravitySpell component2 = val2.GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)component2 == (Object)null) { Plugin.Log.LogError((object)"Zawardo was not installed: VoiceSpell, Vento, or the native AntiGravitySpell component is missing."); return; } ProtectionSpell protectionSpell = ((val3 != null) ? val3.GetComponent() : null); GameObject obj = FindPrefab(manager, "TeleportDungeonCircle"); TeleportDungeonCircle startCircle = ((obj != null) ? obj.GetComponent() : null) ?? ((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((TeleportDungeonCircle circle) => (Object)(object)circle != (Object)null)); EnsureRuntimeData(val4, component2, protectionSpell, startCircle); EnsureSpellOnWand(val, component); } private static GameObject FindPrefab(YapNetworkManager manager, string name) { return ((IEnumerable)((NetworkManager)manager).spawnPrefabs).FirstOrDefault((Func)((GameObject prefab) => (Object)(object)prefab != (Object)null && string.Equals(((Object)prefab).name, name, StringComparison.Ordinal))); } private static void EnsureRuntimeData(Spell vento, AntiGravitySpell antiGravity, ProtectionSpell protectionSpell, TeleportDungeonCircle startCircle) { //IL_010d: 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_01bd: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) object? value = AntiGravityVfxField.GetValue(antiGravity); antiGravityVfx = (GameObject)((value is GameObject) ? value : null); StatusProtectionSO val = (StatusProtectionSO)(((Object)(object)protectionSpell == (Object)null) ? ((object)((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((StatusProtectionSO status) => (Object)(object)status != (Object)null && string.Equals(((Object)status).name, "StatusProtection", StringComparison.Ordinal) && (Object)(object)status.protectionVFX != (Object)null))) : ((object)/*isinst with value type is only supported in some contexts*/)); object obj = (object)(((Object)(object)startCircle == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); areaVfx = (GameObject)(obj ?? (((Object)(object)val == (Object)null) ? antiGravityVfx : val.protectionVFX)); areaVfxScale = (((Object)obj == (Object)null) ? 14f : 3.5f); custodiaVfx = (((Object)(object)val == (Object)null) ? null : val.protectionVFX); if ((Object)(object)custodiaVfx != (Object)null) { Plugin.Log.LogInfo((object)("[TheWorld] Custodia VFX found=" + ((Object)custodiaVfx).name)); } else { Plugin.Log.LogWarning((object)"[TheWorld] Custodia VFX was not resolved; the zone will use the existing start-circle fallback."); } EventReference castEvent = (EventReference)AntiGravitySfxField.GetValue(antiGravity); if (!((Object)(object)zawardoSpellData != (Object)null)) { zawardoSpellData = Object.Instantiate(vento.SpellData); ((Object)zawardoSpellData).name = "SD_BAS_ZAWARDO_MOD"; zawardoSpellData.spellName = "THE WORLD"; zawardoSpellData.voiceCommandKey = "MOD_SPELL_BAS_ZAWARDO"; zawardoSpellData.cooldown = 150f; zawardoSpellData.charges = 1; zawardoSpellData.chargePerCast = 1; zawardoSpellData.chargeCostPerSecondCast = 0; zawardoSpellData.chargeRegenInterval = 150f; zawardoSpellData.chargesRegenPerInterval = 1; zawardoSpellData.chargeRegenDelay = 0f; zawardoSpellData.spawnLocation = (SpawnLocation)0; zawardoSpellData.spawnOffset = Vector3.zero; zawardoSpellData.applyLookTransform = false; zawardoSpellData.spawnDelay = 0f; zawardoSpellData.objectToSpawnPrefab = null; zawardoSpellData.castVFXPrefab = antiGravityVfx; zawardoSpellData.spawnVFXPrefab = null; zawardoSpellData.impactVFXPrefab = null; zawardoSpellData.castEvent = castEvent; Plugin.Log.LogInfo((object)("Prepared The World from Wand of Winds and the native Anti-Gravity VFX: 10s duration, one charge, " + $"{150f:0}s test cooldown, " + $"{14f:0}m radius using the native " + "Custodia VFX_Blessed_Bubble prefab.")); } } private static void EnsureSpellOnWand(GameObject windsWand, VoiceSpell voiceSpell) { ZawardoSpell zawardoSpell = windsWand.GetComponent() ?? windsWand.AddComponent(); zawardoSpell.Configure(zawardoSpellData, antiGravityVfx, areaVfx, areaVfxScale, custodiaVfx); ((Behaviour)zawardoSpell).enabled = true; Spell[] array = (VoiceSpellsField.GetValue(voiceSpell) as Spell[]) ?? Array.Empty(); if (!array.Contains((Spell)(object)zawardoSpell)) { VoiceSpellsField.SetValue(voiceSpell, array.Concat((IEnumerable)(object)new Spell[1] { zawardoSpell }).ToArray()); Plugin.Log.LogInfo((object)("Added The World to PropWandOfBasics " + $"({array.Length + 1} total spell entries).")); } } } public sealed class ZawardoSpell : Spell { private sealed class PawnState { internal bool ControllerWasPaused; internal bool ViewWasPaused; } private sealed class BodyState { internal bool UseGravity; internal bool WasKinematic; internal RigidbodyConstraints Constraints; internal float LinearDamping; internal float AngularDamping; internal Vector3 LinearVelocity; internal Vector3 AngularVelocity; internal Vector3 PendingLinearVelocity; internal Vector3 PendingAngularVelocity; internal bool HasPendingMotion; internal bool IsManipulated; } private sealed class NpcState { internal bool MachineWasPaused; internal float AnimatorSpeed; internal NavMeshAgent Agent; internal bool AgentStateCaptured; internal bool AgentWasStopped; internal bool NavigationStateCaptured; internal bool NavigationWasEnabled; } private sealed class SuspendedSpellState { internal float SuspendedAt; internal BaseProjectile Projectile; internal float ProjectileSpawnTime; internal bool HasProjectileSpawnTime; } internal const float DurationSeconds = 10f; internal const float CooldownSeconds = 150f; internal const float EffectRadius = 14f; private const float FrozenLinearDamping = 8f; private const float FrozenAngularDamping = 8f; private const float RescanInterval = 0.25f; private static readonly List Instances = new List(); private static ZawardoSpell activeServerSpell; private static readonly FieldInfo ProjectileCasterField = typeof(BaseProjectile).GetField("Caster", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo ProjectileSpawnTimeField = typeof(BaseProjectile).GetField("spawnTime", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo TimedBombOwnerField = typeof(TimedBomb).GetField("_owner", BindingFlags.Instance | BindingFlags.NonPublic); private readonly Dictionary bodyStates = new Dictionary(); private readonly Dictionary pawnStates = new Dictionary(); private readonly Dictionary npcStates = new Dictionary(); private readonly Dictionary suspendedSpellBehaviours = new Dictionary(); private GameObject timeStopVfx; private GameObject areaVfx; private GameObject custodiaVfx; private float areaVfxScale = 14f; private Vector3 stopCenter; private float stopEndTime; private float nextRescanTime; private bool serverStopActive; public override bool IsInstantCast => false; internal static ZawardoSpell ActiveClientSpell => Instances.FirstOrDefault((ZawardoSpell spell) => (Object)(object)spell != (Object)null && ((Spell)spell).IsCasting && (Object)(object)((Spell)spell).CasterIdentity != (Object)null); internal GameObject AreaVfx => areaVfx; internal GameObject CustodiaVfx => custodiaVfx; internal float AreaVfxScale => areaVfxScale; internal void Configure(SpellData data, GameObject vfx, GameObject radiusVfx, float radiusScale, GameObject custodiaZoneVfx) { base.spellData = data; timeStopVfx = vfx; areaVfx = radiusVfx; areaVfxScale = radiusScale; custodiaVfx = custodiaZoneVfx; } internal static bool IsInsideArea(Vector3 position, Vector3 center) { //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 = position - center; return ((Vector3)(ref val)).sqrMagnitude <= 196f; } internal static NetworkIdentity GetProjectileCaster(BaseProjectile projectile) { if (!((Object)(object)projectile == (Object)null)) { object? obj = ProjectileCasterField?.GetValue(projectile); return (NetworkIdentity)((obj is NetworkIdentity) ? obj : null); } return null; } internal static NetworkIdentity GetTimedBombOwner(TimedBomb bomb) { if (!((Object)(object)bomb == (Object)null)) { object? obj = TimedBombOwnerField?.GetValue(bomb); return (NetworkIdentity)((obj is NetworkIdentity) ? obj : null); } return null; } internal static bool ShouldPauseTimedBomb(TimedBomb bomb) { //IL_0046: 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) if (NetworkServer.active && (Object)(object)bomb != (Object)null && (Object)(object)activeServerSpell != (Object)null && activeServerSpell.serverStopActive && (Object)(object)GetTimedBombOwner(bomb) != (Object)(object)((Spell)activeServerSpell).NetworkcasterIdentity) { return IsInsideArea(((Component)bomb).transform.position, activeServerSpell.stopCenter); } return false; } private void OnEnable() { if (!Instances.Contains(this)) { Instances.Add(this); } } private void OnDisable() { Instances.Remove(this); if (serverStopActive) { RestoreServerState(); } } private void OnDestroy() { Instances.Remove(this); if (serverStopActive) { RestoreServerState(); } } public override bool CanCast() { if (((Spell)this).CanCast()) { if (!((Object)(object)activeServerSpell == (Object)null)) { return (Object)(object)activeServerSpell == (Object)(object)this; } return true; } return false; } [Server] public override void CastSpell() { if (!NetworkServer.active) { Debug.LogWarning((object)"[ZawardoSpell] Cast attempted while server was inactive."); } else if (((Spell)this).CanCast()) { ((Spell)this).OnSpellActivate(); } } [ServerCallback] public override void StopSpell() { if (NetworkServer.active && base.isCasting && (!serverStopActive || !(Time.time < stopEndTime))) { ((Spell)this).OnSpellDeactivate(); } } [ServerCallback] public override void OnSpellActivate() { //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) if (NetworkServer.active && !serverStopActive) { ((Spell)this).OnSpellActivate(); activeServerSpell = this; serverStopActive = true; stopCenter = ((Component)((Spell)this).NetworkcasterIdentity).transform.position; stopEndTime = Time.time + 10f; nextRescanTime = Time.time; CaptureNewServerTargets(spawnVfx: true); SpawnCastIndicator(); ManualLogSource log = Plugin.Log; NetworkIdentity networkcasterIdentity = ((Spell)this).NetworkcasterIdentity; log.LogInfo((object)("Zawardo time stop started by " + (((networkcasterIdentity != null) ? ((Object)networkcasterIdentity).name : null) ?? "unknown caster") + " for " + $"{10f:0}s.")); } } [ServerCallback] public override void OnSpellDeactivate() { if (NetworkServer.active) { RestoreServerState(); ((Spell)this).OnSpellDeactivate(); if (!((Spell)this).HasInfiniteCharges && base.currentCharges < ((Spell)this).MaxCharges) { ((Spell)this).NetworkregenerationStartTime = base.lastCastTime; ((Spell)this).NetworkchargesAtRegenStart = base.currentCharges; } } } public override void Update() { if (!((NetworkBehaviour)this).isServer) { return; } if (serverStopActive) { if (Time.time >= stopEndTime) { ((Spell)this).OnSpellDeactivate(); } else if (Time.time >= nextRescanTime) { nextRescanTime = Time.time + 0.25f; CaptureNewServerTargets(spawnVfx: true); } } else { ((Spell)this).Update(); } } private void FixedUpdate() { if (((NetworkBehaviour)this).isServer && serverStopActive) { MaintainFrozenBodies(); } } [Server] private void CaptureNewServerTargets(bool spawnVfx) { //IL_0051: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017a: 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_0206: 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_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0271: 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_0276: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: 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) if (!NetworkServer.active || (Object)(object)((Spell)this).NetworkcasterIdentity == (Object)null) { return; } Pawn[] array = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (Pawn val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((NetworkBehaviour)val).netIdentity == (Object)(object)((Spell)this).NetworkcasterIdentity) && IsInsideArea(((Component)val).transform.position, stopCenter) && !pawnStates.ContainsKey(val)) { PawnState pawnState = new PawnState { ControllerWasPaused = ((Object)(object)val.ControllerStateMachine != (Object)null && ((NetworkStateMachine)(object)val.ControllerStateMachine).IsPaused), ViewWasPaused = ((Object)(object)val.ViewStateMachine != (Object)null && ((NetworkStateMachine)(object)val.ViewStateMachine).IsPaused) }; pawnStates.Add(val, pawnState); int inputLock = val.InputLock; val.InputLock = inputLock + 1; inputLock = val.SilencedLocks; val.SilencedLocks = inputLock + 1; if ((Object)(object)val.ControllerStateMachine != (Object)null && !pawnState.ControllerWasPaused) { ((NetworkStateMachine)(object)val.ControllerStateMachine).Pause(); } if ((Object)(object)val.ViewStateMachine != (Object)null && !pawnState.ViewWasPaused) { ((NetworkStateMachine)(object)val.ViewStateMachine).Pause(); } if (spawnVfx) { SpawnTargetIndicator(((NetworkBehaviour)val).netIdentity); } } } NpcBehaviour[] array2 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (NpcBehaviour val2 in array2) { if (!((Object)(object)val2 == (Object)null) && IsInsideArea(((Component)val2).transform.position, stopCenter) && !npcStates.ContainsKey(val2)) { NpcState npcState = CaptureNpcState(val2); npcStates.Add(val2, npcState); FreezeNpc(val2, npcState); if (spawnVfx) { SpawnTargetIndicator(((NetworkBehaviour)val2).netIdentity); } } } Rigidbody[] array3 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (Rigidbody val3 in array3) { if (IsNativeTimeStopBody(val3) && IsInsideArea(((Component)((Component)val3).GetComponentInParent()).transform.position, stopCenter) && !bodyStates.ContainsKey(val3)) { bodyStates.Add(val3, new BodyState { UseGravity = val3.useGravity, LinearVelocity = (val3.isKinematic ? Vector3.zero : val3.linearVelocity), AngularVelocity = (val3.isKinematic ? Vector3.zero : val3.angularVelocity), WasKinematic = val3.isKinematic, Constraints = val3.constraints, LinearDamping = val3.linearDamping, AngularDamping = val3.angularDamping }); val3.useGravity = false; if (!val3.isKinematic) { val3.linearVelocity = Vector3.zero; val3.angularVelocity = Vector3.zero; val3.linearDamping = 8f; val3.angularDamping = 8f; } } } CaptureNewSpellEffects(); } private void CaptureNewSpellEffects() { //IL_00a6: 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_0043: 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_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_0163: 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) Spell[] array = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (Spell val in array) { NetworkIdentity val2 = ((val != null) ? val.CasterIdentity : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)((Spell)this).NetworkcasterIdentity) && IsInsideArea(((Component)val2).transform.position, stopCenter)) { SuspendSpawnedObjects(val); SuspendSpellBehaviour((Behaviour)(object)val, null); } } BaseProjectile[] array2 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (BaseProjectile val3 in array2) { if (!((Object)(object)val3 == (Object)null) && !((Object)(object)GetProjectileCaster(val3) == (Object)(object)((Spell)this).NetworkcasterIdentity) && IsInsideArea(((Component)val3).transform.position, stopCenter)) { SuspendSpellBehaviour((Behaviour)(object)val3, val3); } } BaseChanneledController[] array3 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (BaseChanneledController val4 in array3) { if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4.Networkcaster == (Object)(object)((Spell)this).NetworkcasterIdentity) && IsInsideArea(((Component)val4).transform.position, stopCenter)) { SuspendSpellBehaviour((Behaviour)(object)val4, null); } } TimedBomb[] array4 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (TimedBomb val5 in array4) { if ((Object)(object)val5 != (Object)null && (Object)(object)GetTimedBombOwner(val5) != (Object)(object)((Spell)this).NetworkcasterIdentity && IsInsideArea(((Component)val5).transform.position, stopCenter)) { SuspendSpellBehaviour((Behaviour)(object)val5, null); } } } private void SuspendSpawnedObjects(Spell ownerSpell) { //IL_0057: 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) if (!(FindFieldInHierarchy(((object)ownerSpell).GetType(), "activeSpawnedObjects")?.GetValue(ownerSpell) is IEnumerable enumerable)) { return; } foreach (object item in enumerable) { Component val = (Component)((item is Component) ? item : null); if (val == null || (Object)(object)val == (Object)null || !IsInsideArea(val.transform.position, stopCenter)) { continue; } Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null); if (val2 != null) { SuspendSpellBehaviour(val2, null); } MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren(true); foreach (MonoBehaviour val3 in componentsInChildren) { if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3 == (Object)(object)val) && (val3 is ISpellSpawnable || val3 is NetworkTimedDestroy || val3 is HitboxBase)) { SuspendSpellBehaviour((Behaviour)(object)val3, null); } } } } private static FieldInfo FindFieldInHierarchy(Type type, string fieldName) { while (type != null) { FieldInfo field = type.GetField(fieldName, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } return null; } private void SuspendSpellBehaviour(Behaviour behaviour, BaseProjectile projectile) { if (!((Object)(object)behaviour == (Object)null) && behaviour.enabled && !suspendedSpellBehaviours.ContainsKey(behaviour)) { SuspendedSpellState suspendedSpellState = new SuspendedSpellState { SuspendedAt = Time.time, Projectile = projectile }; if ((Object)(object)projectile != (Object)null && ProjectileSpawnTimeField != null) { suspendedSpellState.ProjectileSpawnTime = (float)ProjectileSpawnTimeField.GetValue(projectile); suspendedSpellState.HasProjectileSpawnTime = true; } suspendedSpellBehaviours.Add(behaviour, suspendedSpellState); behaviour.enabled = false; } } private void MaintainFrozenBodies() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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) HashSet casterManipulatedIdentities = GetCasterManipulatedIdentities(); KeyValuePair[] array = bodyStates.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair keyValuePair = array[i]; Rigidbody key = keyValuePair.Key; BodyState value = keyValuePair.Value; if ((Object)(object)key == (Object)null) { continue; } NetworkIdentity componentInParent = ((Component)key).GetComponentInParent(); bool flag = (Object)(object)componentInParent != (Object)null && casterManipulatedIdentities.Contains(componentInParent); key.useGravity = false; if (key.isKinematic) { value.IsManipulated = flag; continue; } if (flag) { key.constraints = value.Constraints; key.linearDamping = value.LinearDamping; key.angularDamping = value.AngularDamping; value.IsManipulated = true; continue; } if (value.IsManipulated) { value.PendingLinearVelocity = key.linearVelocity; value.PendingAngularVelocity = key.angularVelocity; value.HasPendingMotion = true; key.linearVelocity = Vector3.zero; key.angularVelocity = Vector3.zero; } value.IsManipulated = false; key.constraints = value.Constraints; key.linearDamping = 8f; key.angularDamping = 8f; } } private HashSet GetCasterManipulatedIdentities() { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Invalid comparison between Unknown and I4 //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); if ((Object)(object)((Spell)this).NetworkcasterIdentity == (Object)null) { return hashSet; } ControlProjectileHand[] array = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (ControlProjectileHand controlProjectileHand in array) { if (!((Object)(object)controlProjectileHand == (Object)null) && controlProjectileHand.HasGrabbedTarget && !((Object)(object)controlProjectileHand.ControlCaster != (Object)(object)((Spell)this).NetworkcasterIdentity) && !((Object)(object)controlProjectileHand.GrabbedBody == (Object)null)) { NetworkIdentity componentInParent = ((Component)controlProjectileHand.GrabbedBody).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { hashSet.Add(componentInParent); } } } Rigidbody[] array2 = bodyStates.Keys.ToArray(); foreach (Rigidbody val in array2) { if ((Object)(object)val == (Object)null) { continue; } NetworkIdentity componentInParent2 = ((Component)val).GetComponentInParent(); NetworkPuppetProp val2 = (((Object)(object)componentInParent2 == (Object)null) ? null : ((Component)componentInParent2).GetComponent()); if ((Object)(object)val2 != (Object)null && (int)val2.CurrentState.state == 1) { PropStateData currentState = val2.CurrentState; if ((Object)(object)((PropStateData)(ref currentState)).InteractorIdentity == (Object)(object)((Spell)this).NetworkcasterIdentity) { hashSet.Add(componentInParent2); } } } return hashSet; } private bool IsNativeTimeStopBody(Rigidbody body) { //IL_00ac: 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_00b7: Invalid comparison between Unknown and I4 //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) if ((Object)(object)body == (Object)null || (Object)(object)((Spell)this).NetworkcasterIdentity == (Object)null || ((Component)body).transform.IsChildOf(((Component)((Spell)this).NetworkcasterIdentity).transform)) { return false; } NetworkIdentity componentInParent = ((Component)body).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null || (Object)(object)componentInParent == (Object)(object)((Spell)this).NetworkcasterIdentity) { return false; } NetworkPuppetProp component = ((Component)componentInParent).GetComponent(); BaseProjectile component2 = ((Component)componentInParent).GetComponent(); if ((Object)(object)component2 != (Object)null && (Object)(object)GetProjectileCaster(component2) == (Object)(object)((Spell)this).NetworkcasterIdentity) { return false; } ControlProjectileHand component3 = ((Component)componentInParent).GetComponent(); if ((Object)(object)component3 != (Object)null && (Object)(object)component3.ControlCaster == (Object)(object)((Spell)this).NetworkcasterIdentity) { return false; } if ((Object)(object)component != (Object)null && (int)component.CurrentState.state == 1) { PropStateData currentState = component.CurrentState; if ((Object)(object)((PropStateData)(ref currentState)).InteractorIdentity == (Object)(object)((Spell)this).NetworkcasterIdentity) { return false; } } if (!((Object)(object)((Component)componentInParent).GetComponent() != (Object)null) && !((Object)(object)((Component)componentInParent).GetComponent() != (Object)null) && !((Object)(object)((Component)componentInParent).GetComponent() != (Object)null) && !((Object)(object)((Component)componentInParent).GetComponent() != (Object)null) && !((Object)(object)component2 != (Object)null) && !((Object)(object)component != (Object)null)) { return (Object)(object)((Component)componentInParent).GetComponent() != (Object)null; } return true; } private static NpcState CaptureNpcState(NpcBehaviour npc) { NpcState npcState = new NpcState { MachineWasPaused = ((Object)(object)npc.stateMachine != (Object)null && npc.stateMachine.IsPaused), AnimatorSpeed = (((Object)(object)npc.Animator == (Object)null) ? 1f : npc.Animator.speed), NavigationStateCaptured = ((Object)(object)npc.npcToggler != (Object)null), NavigationWasEnabled = ((Object)(object)npc.npcToggler != (Object)null && npc.npcToggler.NetworknavigationEnabled) }; NavMeshAgent agent = npc.Agent; if ((Object)(object)agent != (Object)null && ((Behaviour)agent).enabled && agent.isOnNavMesh) { npcState.Agent = agent; npcState.AgentStateCaptured = true; npcState.AgentWasStopped = agent.isStopped; } return npcState; } private static void FreezeNpc(NpcBehaviour npc, NpcState state) { if ((Object)(object)npc.stateMachine != (Object)null && !state.MachineWasPaused) { npc.stateMachine.Pause(); } if ((Object)(object)npc.Animator != (Object)null) { npc.Animator.speed = 0f; } if (state.AgentStateCaptured && (Object)(object)state.Agent != (Object)null && ((Behaviour)state.Agent).enabled && state.Agent.isOnNavMesh) { state.Agent.isStopped = true; } } [Server] private void SpawnCastIndicator() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)timeStopVfx == (Object)null) && !((Object)(object)VfxManager.Instance == (Object)null) && !((Object)(object)GameManager.Instance == (Object)null) && !((Object)(object)((Spell)this).NetworkcasterIdentity == (Object)null)) { int vfxId = VfxManager.Instance.GetVfxId(timeStopVfx); GameManager.Instance.RpcSpawnVfx(vfxId, ((Component)((Spell)this).NetworkcasterIdentity).transform.position); } } [Server] private void SpawnTargetIndicator(NetworkIdentity target) { if (!((Object)(object)timeStopVfx == (Object)null) && !((Object)(object)VfxManager.Instance == (Object)null) && !((Object)(object)GameManager.Instance == (Object)null) && !((Object)(object)target == (Object)null)) { int vfxId = VfxManager.Instance.GetVfxId(timeStopVfx); GameManager.Instance.RpcSpawnVfxOnEntity(vfxId, target.netId, 10f); } } private void RestoreServerState() { //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_0300: 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_02e2: Unknown result type (might be due to invalid IL or missing references) if (!serverStopActive) { return; } KeyValuePair[] array = pawnStates.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair keyValuePair = array[i]; Pawn key = keyValuePair.Key; PawnState value = keyValuePair.Value; if (!((Object)(object)key == (Object)null)) { key.InputLock = Mathf.Max(0, key.InputLock - 1); key.SilencedLocks = Mathf.Max(0, key.SilencedLocks - 1); if ((Object)(object)key.ControllerStateMachine != (Object)null && !value.ControllerWasPaused && ((NetworkStateMachine)(object)key.ControllerStateMachine).IsPaused) { ((NetworkStateMachine)(object)key.ControllerStateMachine).Resume(); } if ((Object)(object)key.ViewStateMachine != (Object)null && !value.ViewWasPaused && ((NetworkStateMachine)(object)key.ViewStateMachine).IsPaused) { ((NetworkStateMachine)(object)key.ViewStateMachine).Resume(); } } } KeyValuePair[] array2 = npcStates.ToArray(); for (int i = 0; i < array2.Length; i++) { KeyValuePair keyValuePair2 = array2[i]; NpcBehaviour key2 = keyValuePair2.Key; NpcState value2 = keyValuePair2.Value; if (!((Object)(object)key2 == (Object)null)) { if ((Object)(object)key2.stateMachine != (Object)null && !value2.MachineWasPaused && key2.stateMachine.IsPaused) { key2.stateMachine.Resume(); } if ((Object)(object)key2.Animator != (Object)null) { key2.Animator.speed = value2.AnimatorSpeed; key2.RefreshAnimatorParameters(); } if (value2.AgentStateCaptured && (Object)(object)value2.Agent != (Object)null && ((Behaviour)value2.Agent).enabled && value2.Agent.isOnNavMesh) { value2.Agent.isStopped = value2.AgentWasStopped; } } } KeyValuePair[] array3 = bodyStates.ToArray(); for (int i = 0; i < array3.Length; i++) { KeyValuePair keyValuePair3 = array3[i]; Rigidbody key3 = keyValuePair3.Key; BodyState value3 = keyValuePair3.Value; if (!((Object)(object)key3 != (Object)null)) { continue; } key3.constraints = value3.Constraints; key3.linearDamping = value3.LinearDamping; key3.angularDamping = value3.AngularDamping; NetworkIdentity componentInParent = ((Component)key3).GetComponentInParent(); NpcBehaviour val = (((Object)(object)componentInParent == (Object)null) ? null : ((Component)componentInParent).GetComponent()); NpcState value4; bool flag = (Object)(object)val != (Object)null && npcStates.TryGetValue(val, out value4) && value4.NavigationStateCaptured && value4.NavigationWasEnabled && (Object)(object)val.npcToggler != (Object)null && !val.npcToggler.NetworknavigationEnabled; key3.useGravity = flag || value3.UseGravity; if (!key3.isKinematic && !value3.WasKinematic && !value3.IsManipulated) { if (value3.HasPendingMotion) { key3.linearVelocity = value3.PendingLinearVelocity; key3.angularVelocity = value3.PendingAngularVelocity; } else { key3.linearVelocity = value3.LinearVelocity; key3.angularVelocity = value3.AngularVelocity; } } } KeyValuePair[] array4 = suspendedSpellBehaviours.ToArray(); for (int i = 0; i < array4.Length; i++) { KeyValuePair keyValuePair4 = array4[i]; Behaviour key4 = keyValuePair4.Key; SuspendedSpellState value5 = keyValuePair4.Value; if (!((Object)(object)key4 == (Object)null)) { if ((Object)(object)value5.Projectile != (Object)null && value5.HasProjectileSpawnTime && ProjectileSpawnTimeField != null) { ProjectileSpawnTimeField.SetValue(value5.Projectile, value5.ProjectileSpawnTime + (Time.time - value5.SuspendedAt)); } key4.enabled = true; } } pawnStates.Clear(); npcStates.Clear(); bodyStates.Clear(); suspendedSpellBehaviours.Clear(); serverStopActive = false; if ((Object)(object)activeServerSpell == (Object)(object)this) { activeServerSpell = null; } Plugin.Log.LogInfo((object)"Zawardo time stop ended; native input, AI, animation, navigation, and gravity states were restored."); } } [HarmonyPatch(typeof(TimedBomb), "Update")] internal static class ZawardoTimedBombUpdatePatch { [HarmonyPrefix] private static bool Prefix(TimedBomb __instance) { return !ZawardoSpell.ShouldPauseTimedBomb(__instance); } } internal sealed class ZawardoClientController : MonoBehaviour { private static readonly FieldInfo CameraInputField = typeof(CameraManager).GetField("input"); private static readonly FieldInfo CameraVolumeField = typeof(CameraManager).GetField("postProcessVolume", BindingFlags.Instance | BindingFlags.NonPublic); private readonly Dictionary animatorSpeeds = new Dictionary(); private readonly Dictionary particleStates = new Dictionary(); private readonly Dictionary clientSpellBehaviourStates = new Dictionary(); private const float CustodiaNativeRadius = 3f; private ZawardoSpell activeSpell; private Vector3 areaCenter; private GameObject areaVfxInstance; private GameObject monochromeVolumeObject; private VolumeProfile monochromeVolumeProfile; private Pawn lockedLocalPawn; private PawnVisionComponent lockedVision; private bool priorCamLookLock; private Behaviour lockedCameraInput; private bool cameraInputWasEnabled; private InputProvider lockedInputProvider; private bool inputProviderWasEnabled; private void Update() { //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) ZawardoSpell activeClientSpell = ZawardoSpell.ActiveClientSpell; if ((Object)(object)activeClientSpell != (Object)(object)activeSpell) { RestoreClientState(); activeSpell = activeClientSpell; if ((Object)(object)activeSpell != (Object)null && (Object)(object)((Spell)activeSpell).CasterIdentity != (Object)null) { areaCenter = ((Component)((Spell)activeSpell).CasterIdentity).transform.position; SpawnAreaVisual(); } } if (!((Object)(object)activeSpell == (Object)null)) { CaptureAndFreezeAnimations(); CaptureAndFreezeSpellEffects(); LockLocalVictimInput(); } } private void OnDisable() { RestoreClientState(); } private void OnDestroy() { RestoreClientState(); } private void CaptureAndFreezeAnimations() { //IL_0039: 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_00a8: 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) //IL_0122: 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) NetworkIdentity casterIdentity = ((Spell)activeSpell).CasterIdentity; Pawn[] array = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (Pawn val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((NetworkBehaviour)val).netIdentity == (Object)(object)casterIdentity) && ZawardoSpell.IsInsideArea(((Component)val).transform.position, areaCenter)) { PawnView view = val.View; Animator animator = ((view == null) ? null : view.NetworkAnimator?.animator); FreezeAnimator(animator); } } if (!NetworkServer.active) { NpcBehaviour[] array2 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (NpcBehaviour val2 in array2) { if ((Object)(object)val2 != (Object)null && ZawardoSpell.IsInsideArea(((Component)val2).transform.position, areaCenter)) { FreezeAnimator(val2.Animator); } } } Animator[] array3 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (Animator val3 in array3) { if (!((Object)(object)val3 == (Object)null) && !(((Component)val3).transform is RectTransform) && !IsCasterOwnedTransform(((Component)val3).transform) && !IsZoneVisualTransform(((Component)val3).transform) && ZawardoSpell.IsInsideArea(((Component)val3).transform.position, areaCenter)) { FreezeAnimator(val3); } } } private void FreezeAnimator(Animator animator) { if (!((Object)(object)animator == (Object)null)) { if (!animatorSpeeds.ContainsKey(animator)) { animatorSpeeds.Add(animator, animator.speed); } animator.speed = 0f; } } private void CaptureAndFreezeSpellEffects() { //IL_0042: 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_00bd: 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_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_0240: 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) BaseProjectile[] array = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (BaseProjectile val in array) { NetworkIdentity projectileCaster = ZawardoSpell.GetProjectileCaster(val); if (!((Object)(object)val == (Object)null) && !((Object)(object)projectileCaster == (Object)null) && !((Object)(object)projectileCaster == (Object)(object)((Spell)activeSpell).CasterIdentity) && ZawardoSpell.IsInsideArea(((Component)val).transform.position, areaCenter)) { FreezeClientSpellBehaviour((Behaviour)(object)val); FreezeParticles(((Component)val).gameObject); } } BaseChanneledController[] array2 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (BaseChanneledController val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.Networkcaster == (Object)null) && !((Object)(object)val2.Networkcaster == (Object)(object)((Spell)activeSpell).CasterIdentity) && ZawardoSpell.IsInsideArea(((Component)val2).transform.position, areaCenter)) { FreezeClientSpellBehaviour((Behaviour)(object)val2); FreezeParticles(((Component)val2).gameObject); } } TimedBomb[] array3 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (TimedBomb val3 in array3) { if (!((Object)(object)val3 == (Object)null) && !((Object)(object)ZawardoSpell.GetTimedBombOwner(val3) == (Object)(object)((Spell)activeSpell).CasterIdentity) && ZawardoSpell.IsInsideArea(((Component)val3).transform.position, areaCenter)) { FreezeClientSpellBehaviour((Behaviour)(object)val3); FreezeParticles(((Component)val3).gameObject); } } MonoBehaviour[] array4 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (MonoBehaviour val4 in array4) { if (val4 is ISpellSpawnable && !(val4 is BaseProjectile) && !(val4 is BaseChanneledController) && ZawardoSpell.IsInsideArea(((Component)val4).transform.position, areaCenter)) { NetworkIdentity val5 = TryGetSpawnableCaster(val4); if (!((Object)(object)val5 == (Object)null) && !((Object)(object)val5 == (Object)(object)((Spell)activeSpell).CasterIdentity)) { FreezeClientSpellBehaviour((Behaviour)(object)val4); FreezeParticles(((Component)val4).gameObject); } } } ParticleSystem[] array5 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (ParticleSystem val6 in array5) { if (!((Object)(object)val6 == (Object)null) && !(((Component)val6).transform is RectTransform) && !IsCasterOwnedTransform(((Component)val6).transform) && !IsZoneVisualTransform(((Component)val6).transform) && ZawardoSpell.IsInsideArea(((Component)val6).transform.position, areaCenter)) { FreezeParticle(val6); } } } private NetworkIdentity TryGetSpawnableCaster(MonoBehaviour behaviour) { HitboxBase val = (HitboxBase)(object)((behaviour is HitboxBase) ? behaviour : null); if (val != null) { return val.owner; } PropertyInfo property = ((object)behaviour).GetType().GetProperty("NetworkcasterIdentity", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(property?.PropertyType == typeof(NetworkIdentity))) { return null; } object? value = property.GetValue(behaviour); return (NetworkIdentity)((value is NetworkIdentity) ? value : null); } private bool IsCasterOwnedTransform(Transform target) { if (!((Object)(object)target == (Object)null)) { ZawardoSpell zawardoSpell = activeSpell; if (!((Object)(object)((zawardoSpell != null) ? ((Spell)zawardoSpell).CasterIdentity : null) == (Object)null)) { Transform transform = ((Component)((Spell)activeSpell).CasterIdentity).transform; if ((Object)(object)target == (Object)(object)transform || target.IsChildOf(transform)) { return true; } BaseProjectile componentInParent = ((Component)target).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)ZawardoSpell.GetProjectileCaster(componentInParent) == (Object)(object)((Spell)activeSpell).CasterIdentity) { return true; } BaseChanneledController componentInParent2 = ((Component)target).GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null && (Object)(object)componentInParent2.Networkcaster == (Object)(object)((Spell)activeSpell).CasterIdentity) { return true; } MonoBehaviour[] componentsInParent = ((Component)target).GetComponentsInParent(true); foreach (MonoBehaviour val in componentsInParent) { if (val is ISpellSpawnable && (Object)(object)TryGetSpawnableCaster(val) == (Object)(object)((Spell)activeSpell).CasterIdentity) { return true; } } return false; } } return false; } private bool IsZoneVisualTransform(Transform target) { if ((Object)(object)areaVfxInstance != (Object)null) { if (!((Object)(object)target == (Object)(object)areaVfxInstance.transform)) { return target.IsChildOf(areaVfxInstance.transform); } return true; } return false; } private void FreezeClientSpellBehaviour(Behaviour behaviour) { if (!((Object)(object)behaviour == (Object)null) && !NetworkServer.active) { if (!clientSpellBehaviourStates.ContainsKey(behaviour)) { clientSpellBehaviourStates.Add(behaviour, behaviour.enabled); } behaviour.enabled = false; } } private void FreezeParticles(GameObject target) { if ((Object)(object)target == (Object)null) { return; } ParticleSystem[] componentsInChildren = target.GetComponentsInChildren(true); foreach (ParticleSystem val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { if (!particleStates.ContainsKey(val)) { particleStates.Add(val, val.isPlaying); } val.Pause(true); } } } private void FreezeParticle(ParticleSystem particles) { if (!particleStates.ContainsKey(particles)) { particleStates.Add(particles, particles.isPlaying); } particles.Pause(true); } private void SpawnAreaVisual() { //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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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) GameObject val = activeSpell?.CustodiaVfx ?? activeSpell?.AreaVfx; if ((Object)(object)val != (Object)null) { areaVfxInstance = (((Object)(object)VfxManager.Instance == (Object)null) ? null : VfxManager.Instance.SpawnVfx(val, areaCenter, Quaternion.identity, (Transform)null, 0f)); if ((Object)(object)areaVfxInstance == (Object)null) { Plugin.Log.LogWarning((object)"The World zone VFX skipped: the game's VfxManager could not spawn the resolved prefab."); } else { ((Object)areaVfxInstance).name = "TheWorldCustodiaRadiusVfx"; areaVfxInstance.SetActive(true); float num = (((Object)(object)activeSpell.CustodiaVfx != (Object)null) ? 4.6666665f : activeSpell.AreaVfxScale); areaVfxInstance.transform.localScale = Vector3.Scale(areaVfxInstance.transform.localScale, Vector3.one * num); Collider[] componentsInChildren = areaVfxInstance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } ParticleSystem[] componentsInChildren2 = areaVfxInstance.GetComponentsInChildren(true); foreach (ParticleSystem obj in componentsInChildren2) { ((Component)obj).gameObject.SetActive(true); obj.Play(true); } Plugin.Log.LogInfo((object)("The World zone VFX spawned through VfxManager: " + $"{((Object)val).name}, radius {14f:0}m.")); } } else { Plugin.Log.LogWarning((object)"The World zone VFX skipped: no verified game VFX prefab was resolved."); } SpawnMonochromeVolume(); } private void SpawnMonochromeVolume() { //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) Volume val = (Volume)(((Object)(object)CameraManager.Instance == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)((val != null) ? val.profile : null) == (Object)null) { ColorAdjustments val3 = default(ColorAdjustments); val = ((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((Volume volume) => (Object)(object)volume != (Object)null && (Object)(object)volume.profile != (Object)null && volume.profile.TryGet(ref val3))); } if ((Object)(object)((val != null) ? val.profile : null) == (Object)null) { Plugin.Log.LogWarning((object)"The World grayscale skipped: the game's camera post-processing Volume was not available."); return; } monochromeVolumeProfile = Object.Instantiate(val.profile); ColorAdjustments val2 = default(ColorAdjustments); if (!monochromeVolumeProfile.TryGet(ref val2)) { Plugin.Log.LogWarning((object)"The World grayscale skipped: the game's active VolumeProfile has no ColorAdjustments component."); Object.Destroy((Object)(object)monochromeVolumeProfile); monochromeVolumeProfile = null; return; } foreach (VolumeComponent component in monochromeVolumeProfile.components) { component.active = (Object)(object)component == (Object)(object)val2; } foreach (VolumeParameter parameter in ((VolumeComponent)val2).parameters) { parameter.overrideState = false; } ((VolumeComponent)val2).active = true; ((VolumeParameter)(object)val2.saturation).Override(-100f); monochromeVolumeObject = new GameObject("TheWorldLocalMonochromeVolume"); monochromeVolumeObject.layer = ((Component)val).gameObject.layer; monochromeVolumeObject.transform.position = areaCenter; SphereCollider obj = monochromeVolumeObject.AddComponent(); ((Collider)obj).isTrigger = true; obj.radius = 14f; Volume obj2 = monochromeVolumeObject.AddComponent(); obj2.isGlobal = false; obj2.priority = val.priority + 100f; obj2.blendDistance = 0.5f; obj2.weight = 1f; obj2.sharedProfile = monochromeVolumeProfile; Plugin.Log.LogInfo((object)("The World local monochrome Volume spawned: " + $"radius {14f:0}m, saturation -100.")); } private void LockLocalVictimInput() { //IL_002d: 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) Pawn localInstance = Pawn.LocalInstance; if ((Object)(object)localInstance == (Object)null || (Object)(object)((Spell)activeSpell).CasterIdentity == (Object)(object)((NetworkBehaviour)localInstance).netIdentity || (!ZawardoSpell.IsInsideArea(((Component)localInstance).transform.position, areaCenter) && (Object)(object)lockedLocalPawn != (Object)(object)localInstance)) { RestoreLocalInput(); return; } if ((Object)(object)lockedLocalPawn != (Object)(object)localInstance) { RestoreLocalInput(); lockedLocalPawn = localInstance; PawnControllerStateMachine controllerStateMachine = localInstance.ControllerStateMachine; lockedVision = ((controllerStateMachine != null) ? controllerStateMachine.VisionComponent : null); if (lockedVision != null) { priorCamLookLock = lockedVision.CamLookLock; } lockedInputProvider = localInstance.InputProvider; if ((Object)(object)lockedInputProvider != (Object)null) { inputProviderWasEnabled = ((Behaviour)lockedInputProvider).enabled; } if ((Object)(object)CameraManager.Instance != (Object)null) { ref Behaviour reference = ref lockedCameraInput; object? obj = CameraInputField?.GetValue(CameraManager.Instance); reference = (Behaviour)((obj is Behaviour) ? obj : null); if ((Object)(object)lockedCameraInput != (Object)null) { cameraInputWasEnabled = lockedCameraInput.enabled; } } } if (lockedVision != null) { lockedVision.CamLookLock = true; } if ((Object)(object)lockedInputProvider != (Object)null) { ((Behaviour)lockedInputProvider).enabled = false; } if ((Object)(object)lockedCameraInput != (Object)null) { lockedCameraInput.enabled = false; } } private void RestoreClientState() { //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) RestoreLocalInput(); KeyValuePair[] array = animatorSpeeds.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair keyValuePair = array[i]; if ((Object)(object)keyValuePair.Key != (Object)null && Mathf.Approximately(keyValuePair.Key.speed, 0f)) { keyValuePair.Key.speed = keyValuePair.Value; } } animatorSpeeds.Clear(); KeyValuePair[] array2 = clientSpellBehaviourStates.ToArray(); for (int i = 0; i < array2.Length; i++) { KeyValuePair keyValuePair2 = array2[i]; if ((Object)(object)keyValuePair2.Key != (Object)null) { keyValuePair2.Key.enabled = keyValuePair2.Value; } } clientSpellBehaviourStates.Clear(); KeyValuePair[] array3 = particleStates.ToArray(); for (int i = 0; i < array3.Length; i++) { KeyValuePair keyValuePair3 = array3[i]; if ((Object)(object)keyValuePair3.Key != (Object)null && keyValuePair3.Value) { keyValuePair3.Key.Play(true); } } particleStates.Clear(); if ((Object)(object)areaVfxInstance != (Object)null) { GameManager.DespawnPrefabInstance(areaVfxInstance, 0f); areaVfxInstance = null; } if ((Object)(object)monochromeVolumeObject != (Object)null) { Object.Destroy((Object)(object)monochromeVolumeObject); monochromeVolumeObject = null; } if ((Object)(object)monochromeVolumeProfile != (Object)null) { Object.Destroy((Object)(object)monochromeVolumeProfile); monochromeVolumeProfile = null; } NpcBehaviour[] array4 = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (NpcBehaviour val in array4) { if ((Object)(object)val != (Object)null && (Object)(object)val.Animator != (Object)null) { val.RefreshAnimatorParameters(); } } activeSpell = null; areaCenter = Vector3.zero; } private void RestoreLocalInput() { if (lockedVision != null) { lockedVision.CamLookLock = priorCamLookLock; } bool flag = (Object)(object)InputManager.Instance != (Object)null && InputManager.Instance.IsInputLocked; if ((Object)(object)lockedInputProvider != (Object)null && inputProviderWasEnabled && !flag) { ((Behaviour)lockedInputProvider).enabled = true; } if ((Object)(object)lockedCameraInput != (Object)null && cameraInputWasEnabled && !flag) { lockedCameraInput.enabled = true; } lockedLocalPawn = null; lockedVision = null; lockedCameraInput = null; lockedInputProvider = null; priorCamLookLock = false; cameraInputWasEnabled = false; inputProviderWasEnabled = false; } }