Decompiled source of SpellEditor v1.1.0

BepInEx/plugins/SpellEditor/SpellEditor.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SpellEditor.SpellForge;
using UnityEngine;
using UnityEngine.SceneManagement;
using YAPYAP;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SpellEditor")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+bc4b4649f47d4453cf14ea973d606f6812266266")]
[assembly: AssemblyProduct("SpellEditor")]
[assembly: AssemblyTitle("SpellEditor")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SpellEditor
{
	public class DummySpawner : MonoBehaviour
	{
		private readonly List<GameObject> _dummies = new List<GameObject>();

		private void Update()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			if (!Input.GetKeyDown((KeyCode)290))
			{
				return;
			}
			if (_dummies.Count > 0)
			{
				DespawnAll();
				return;
			}
			if (!NetworkServer.active)
			{
				Plugin.Log.LogWarning((object)"[DummySpawner] Must be the server host to spawn dummies.");
				return;
			}
			GameObject val = FindAIPawnPrefab();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[DummySpawner] No PawnAIFollower prefab found in registered network prefabs.");
				return;
			}
			NetworkIdentity localPlayer = NetworkClient.localPlayer;
			Pawn val2 = ((localPlayer != null) ? ((Component)localPlayer).GetComponent<Pawn>() : null);
			Vector3 val3 = ((!((Object)(object)val2 != (Object)null)) ? (Vector3.forward * 4f) : (((Component)val2).transform.position + ((Component)val2).transform.forward * 4f));
			GameObject val4 = Object.Instantiate<GameObject>(val, val3, Quaternion.identity);
			NetworkServer.Spawn(val4, (NetworkConnectionToClient)null);
			PawnAIFollower component = val4.GetComponent<PawnAIFollower>();
			if ((Object)(object)component != (Object)null)
			{
				component.ExternalControlEnabled = true;
				AIInputProvider component2 = val4.GetComponent<AIInputProvider>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.UsePathfinding = false;
					component2.StoppingDistance = 0.1f;
				}
			}
			_dummies.Add(val4);
			Plugin.Log.LogInfo((object)$"[DummySpawner] Spawned AI dummy at {val3}. Press F9 to despawn.");
		}

		private static GameObject? FindAIPawnPrefab()
		{
			foreach (GameObject spawnPrefab in NetworkManager.singleton.spawnPrefabs)
			{
				if ((Object)(object)spawnPrefab != (Object)null && (Object)(object)spawnPrefab.GetComponent<PawnAIFollower>() != (Object)null)
				{
					return spawnPrefab;
				}
			}
			return null;
		}

		private void DespawnAll()
		{
			foreach (GameObject dummy in _dummies)
			{
				if (!((Object)(object)dummy == (Object)null))
				{
					NetworkServer.UnSpawn(dummy);
					Object.Destroy((Object)(object)dummy);
				}
			}
			Plugin.Log.LogInfo((object)$"[DummySpawner] Despawned {_dummies.Count} dummy(s).");
			_dummies.Clear();
		}

		private void OnDestroy()
		{
			DespawnAll();
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct FlightRequestMessage : NetworkMessage
	{
	}
	public static class FlightCommand
	{
		[HarmonyPatch(typeof(NetworkManager), "OnStartServer")]
		public static class OnStartServerPatch
		{
			public static void Postfix()
			{
				RegisterHandlers();
			}
		}

		[HarmonyPatch(typeof(NetworkManager), "OnStartClient")]
		public static class OnStartClientPatch
		{
			public static void Postfix()
			{
				RegisterHandlers();
			}
		}

		[HarmonyPatch(typeof(PawnVoiceCommands), "Start")]
		public static class PawnVoiceCommandsStartPatch
		{
			public static void Postfix(PawnVoiceCommands __instance)
			{
				Pawn component = ((Component)__instance).GetComponent<Pawn>();
				if (!((Object)(object)component == (Object)null) && ((NetworkBehaviour)component).isLocalPlayer && !((Object)(object)component.Voice == (Object)null))
				{
					PawnVoice voice = component.Voice;
					voice.OnVoiceResult = (Action<string>)Delegate.Combine(voice.OnVoiceResult, new Action<string>(OnVoiceResult));
					if ((Object)(object)UIManager.Instance?.uiChat != (Object)null)
					{
						UIManager.Instance.uiChat.OnMessageSendVoice += OnVoiceResult;
					}
					Plugin.Log.LogInfo((object)"[FlightCommand] Voice listener registered on local player.");
				}
			}
		}

		[HarmonyPatch(typeof(StatusFlying), "OnFixedUpdate")]
		public static class StatusFlyingLandingPatch
		{
			public static void Postfix(StatusFlying __instance)
			{
				//IL_005e: 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_007b: Unknown result type (might be due to invalid IL or missing references)
				object? obj = _pawnField?.GetValue(__instance);
				Pawn val = (Pawn)((obj is Pawn) ? obj : null);
				if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).isServer)
				{
					return;
				}
				Rigidbody rigidbody = val.Rigidbody;
				if ((Object)(object)rigidbody == (Object)null)
				{
					return;
				}
				_activationTimes.TryGetValue(((Object)val).GetInstanceID(), out var value);
				if (!(Time.time - value < 3f) && !(rigidbody.linearVelocity.y > 0.5f) && Physics.Raycast(((Component)val).transform.position, Vector3.down, 2f))
				{
					StatusFlying lastStatus = val.PawnStatus.GetLastStatus<StatusFlying>();
					if (lastStatus != null)
					{
						val.PawnStatus.RemoveStatus((Status)(object)lastStatus);
					}
				}
			}
		}

		private const string LocKey = "PLAYER_COMMAND_BECOME_WIND";

		private const float Duration = 60f;

		private static StatusFlyingSO? _statusSO;

		private static readonly Dictionary<int, float> _activationTimes = new Dictionary<int, float>();

		private const float GracePeriod = 3f;

		private static readonly FieldInfo _pawnField = typeof(Status).GetField("_pawn", BindingFlags.Instance | BindingFlags.NonPublic);

		private const float LandingRayDistance = 2f;

		public static void RegisterHandlers()
		{
			try
			{
				NetworkServer.RegisterHandler<FlightRequestMessage>((Action<NetworkConnectionToClient, FlightRequestMessage>)OnServerReceive, false);
			}
			catch
			{
			}
			try
			{
				NetworkClient.RegisterHandler<FlightRequestMessage>((Action<FlightRequestMessage>)OnClientReceive, false);
			}
			catch
			{
			}
		}

		private static void OnVoiceResult(string input)
		{
			if (string.IsNullOrEmpty(input) || !MatchesTrigger(input))
			{
				return;
			}
			if (NetworkServer.active)
			{
				Pawn val = ((IEnumerable<Pawn>)Object.FindObjectsByType<Pawn>((FindObjectsSortMode)0)).FirstOrDefault((Func<Pawn, bool>)((Pawn p) => ((NetworkBehaviour)p).isLocalPlayer));
				if ((Object)(object)val != (Object)null)
				{
					Apply(val);
				}
			}
			else if (NetworkClient.isConnected)
			{
				NetworkClient.Send<FlightRequestMessage>(default(FlightRequestMessage), 0);
			}
		}

		private static bool MatchesTrigger(string input)
		{
			string[] currentWords = VoiceInjector.GetCurrentWords("PLAYER_COMMAND_BECOME_WIND", (SystemLanguage)10);
			if (currentWords == null || currentWords.Length == 0)
			{
				return false;
			}
			int num = -1;
			string[] array = currentWords;
			foreach (string text in array)
			{
				int num2 = input.IndexOf(text, num + 1, StringComparison.OrdinalIgnoreCase);
				if (num2 < 0)
				{
					return false;
				}
				num = num2 + text.Length - 1;
			}
			return true;
		}

		private static void OnServerReceive(NetworkConnectionToClient conn, FlightRequestMessage msg)
		{
			NetworkIdentity identity = ((NetworkConnection)conn).identity;
			Pawn val = ((identity != null) ? ((Component)identity).GetComponent<Pawn>() : null);
			if ((Object)(object)val != (Object)null)
			{
				Apply(val);
			}
		}

		private static void OnClientReceive(FlightRequestMessage msg)
		{
		}

		private static void Apply(Pawn pawn)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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)
			if (!NetworkServer.active)
			{
				return;
			}
			StatusFlyingSO statusFlyingSO = GetStatusFlyingSO();
			if ((Object)(object)statusFlyingSO == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[FlightCommand] StatusFlyingSO not found in resources.");
				return;
			}
			PawnInventory component = ((Component)pawn).GetComponent<PawnInventory>();
			if (component != null)
			{
				component.SvDropAllItemsFromInventory();
			}
			PawnPropInteractions component2 = ((Component)pawn).GetComponent<PawnPropInteractions>();
			if ((Object)(object)component2 != (Object)null)
			{
				NetworkPuppetProp networkCurrentRightHandNetworkProp = component2.NetworkCurrentRightHandNetworkProp;
				NetworkPuppetProp networkCurrentLeftHandNetworkProp = component2.NetworkCurrentLeftHandNetworkProp;
				if (networkCurrentRightHandNetworkProp != null)
				{
					networkCurrentRightHandNetworkProp.ServerHandleDrop(true, default(Vector3));
				}
				if ((Object)(object)networkCurrentLeftHandNetworkProp != (Object)(object)networkCurrentRightHandNetworkProp && networkCurrentLeftHandNetworkProp != null)
				{
					networkCurrentLeftHandNetworkProp.ServerHandleDrop(true, default(Vector3));
				}
			}
			_activationTimes[((Object)pawn).GetInstanceID()] = Time.time;
			pawn.PawnStatus.AddStatus((StatusSO)(object)statusFlyingSO, 60f, 0f);
			Plugin.Log.LogInfo((object)$"[FlightCommand] StatusFlying applied to {((Object)pawn).name} for {60f}s.");
		}

		private static StatusFlyingSO? GetStatusFlyingSO()
		{
			if ((Object)(object)_statusSO != (Object)null)
			{
				return _statusSO;
			}
			_statusSO = Resources.FindObjectsOfTypeAll<StatusFlyingSO>().FirstOrDefault();
			return _statusSO;
		}
	}
	public class NetworkSync : MonoBehaviour
	{
		[HarmonyPatch(typeof(NetworkManager), "OnStartServer")]
		public static class ServerStartPatch
		{
			public static void Postfix()
			{
				TryRegisterHandlers();
			}
		}

		[HarmonyPatch(typeof(NetworkManager), "OnStartClient")]
		public static class ClientStartPatch
		{
			public static void Postfix()
			{
				TryRegisterHandlers();
			}
		}

		public static NetworkSync? Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
		}

		private void Start()
		{
			TryRegisterHandlers();
		}

		public static void TryRegisterHandlers()
		{
			try
			{
				NetworkServer.RegisterHandler<WandSpellFieldMessage>((Action<NetworkConnectionToClient, WandSpellFieldMessage>)OnServerReceive, false);
			}
			catch
			{
			}
			try
			{
				NetworkClient.RegisterHandler<WandSpellFieldMessage>((Action<WandSpellFieldMessage>)OnClientReceive, false);
			}
			catch
			{
			}
		}

		public void BroadcastFieldChange(NetworkPuppetWandProp wand, string fieldName, string value)
		{
			WandSpellFieldMessage wandSpellFieldMessage = new WandSpellFieldMessage
			{
				WandNetId = WandRegistry.GetWandId(wand),
				FieldName = fieldName,
				FieldValue = value
			};
			if (NetworkServer.active)
			{
				NetworkServer.SendToAll<WandSpellFieldMessage>(wandSpellFieldMessage, 0, false);
			}
			else if (NetworkClient.isConnected)
			{
				NetworkClient.Send<WandSpellFieldMessage>(wandSpellFieldMessage, 0);
			}
			else
			{
				ApplyFieldChange(wandSpellFieldMessage);
			}
		}

		private static void ApplyFieldChange(WandSpellFieldMessage msg)
		{
			NetworkPuppetWandProp val = ((IEnumerable<NetworkPuppetWandProp>)WandRegistry.All).FirstOrDefault((Func<NetworkPuppetWandProp, bool>)((NetworkPuppetWandProp w) => WandRegistry.GetWandId(w) == msg.WandNetId));
			if ((Object)(object)val == (Object)null)
			{
				WandRegistry.Refresh();
				val = ((IEnumerable<NetworkPuppetWandProp>)WandRegistry.All).FirstOrDefault((Func<NetworkPuppetWandProp, bool>)((NetworkPuppetWandProp w) => WandRegistry.GetWandId(w) == msg.WandNetId));
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("NetworkSync: wand '" + msg.WandNetId + "' not found."));
				return;
			}
			Spell spell = val.Spell;
			SpellData val2 = ((spell != null) ? spell.SpellData : null);
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)("NetworkSync: wand '" + msg.WandNetId + "' has no SpellData."));
				return;
			}
			FieldInfo field = typeof(SpellData).GetField(msg.FieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				Plugin.Log.LogWarning((object)("NetworkSync: field '" + msg.FieldName + "' not found on SpellData."));
				return;
			}
			try
			{
				object obj = SpellEditorWindow.ParseValue(field.FieldType, msg.FieldValue);
				if (obj != null)
				{
					field.SetValue(val2, obj);
				}
				Plugin.Log.LogInfo((object)("NetworkSync: applied " + msg.FieldName + "=" + msg.FieldValue + " to wand " + msg.WandNetId + "."));
			}
			catch
			{
				Plugin.Log.LogWarning((object)("NetworkSync: could not parse '" + msg.FieldValue + "' for field '" + msg.FieldName + "'."));
			}
		}

		private static void OnServerReceive(NetworkConnectionToClient conn, WandSpellFieldMessage msg)
		{
			ApplyFieldChange(msg);
			NetworkServer.SendToAll<WandSpellFieldMessage>(msg, 0, false);
		}

		private static void OnClientReceive(WandSpellFieldMessage msg)
		{
			if (!NetworkServer.active)
			{
				ApplyFieldChange(msg);
			}
		}
	}
	public struct WandSpellFieldMessage : NetworkMessage
	{
		public string WandNetId;

		public string FieldName;

		public string FieldValue;
	}
	public static class OculusTempestVariant
	{
		[HarmonyPatch(typeof(ProjectileTornado), "Fire")]
		public static class OculusTornadoSpawnPatch
		{
			public static void Postfix(ProjectileTornado __instance)
			{
				object? obj = _ownerSpellField?.GetValue(__instance);
				object? obj2 = ((obj is Spell) ? obj : null);
				if (((obj2 == null) ? null : ((Spell)obj2).SpellData?.voiceCommandKey) == "SPELL_BAS_OCULUS_TEMPEST")
				{
					_oculusTornadoes.Add(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(ProjectileTornado), "FixedUpdate")]
		public static class OculusTempestMovementPatch
		{
			public static void Postfix(ProjectileTornado __instance)
			{
				//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_0084: 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 (!((NetworkBehaviour)__instance).isServer || !_oculusTornadoes.Contains(__instance))
				{
					return;
				}
				object? obj = _casterField?.GetValue(__instance);
				NetworkIdentity val = (NetworkIdentity)((obj is NetworkIdentity) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Pawn component = ((Component)val).GetComponent<Pawn>();
				if (!((Object)(object)component == (Object)null))
				{
					Vector3 aimDirection = component.Blackboard.AimDirection;
					aimDirection.y = 0f;
					if (!(((Vector3)(ref aimDirection)).sqrMagnitude < 0.01f))
					{
						((Vector3)(ref aimDirection)).Normalize();
						_baseDirectionField?.SetValue(__instance, aimDirection);
						_targetDirectionField?.SetValue(__instance, aimDirection);
						_isChangingDirectionField?.SetValue(__instance, false);
						_nextDirectionChangeTimeField?.SetValue(__instance, Time.time + 9999f);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ProjectileTornado), "OnDestroy")]
		public static class OculusTornadoDestroyPatch
		{
			public static void Postfix(ProjectileTornado __instance)
			{
				_oculusTornadoes.Remove(__instance);
			}
		}

		private static readonly BindingFlags BF = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly FieldInfo _baseDirectionField = typeof(ProjectileTornado).GetField("baseDirection", BF);

		private static readonly FieldInfo _targetDirectionField = typeof(ProjectileTornado).GetField("targetDirection", BF);

		private static readonly FieldInfo _nextDirectionChangeTimeField = typeof(ProjectileTornado).GetField("nextDirectionChangeTime", BF);

		private static readonly FieldInfo _isChangingDirectionField = typeof(ProjectileTornado).GetField("isChangingDirection", BF);

		private static readonly FieldInfo _casterField = typeof(BaseProjectile).GetField("Caster", BF);

		private const string OculusKey = "SPELL_BAS_OCULUS_TEMPEST";

		private static readonly FieldInfo _ownerSpellField = typeof(BaseProjectile).GetField("OwnerSpell", BF);

		private static readonly HashSet<ProjectileTornado> _oculusTornadoes = new HashSet<ProjectileTornado>();

		public static void RegisterProjectilePrefab(GameObject prefab)
		{
		}
	}
	[BepInPlugin("com.local.yapyap.SpellEditor", "SpellEditor", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.local.yapyap.SpellEditor";

		public const string Name = "SpellEditor";

		public const string Version = "1.1.0";

		private static readonly Dictionary<string, string> RequiredVoiceEntries = new Dictionary<string, string>
		{
			{ "SPELL_BAS_FEATHER_FALL", "FEATHER-FALL" },
			{ "SPELL_BAS_DOWN_DOG", "DOWN-DOG" },
			{ "SPELL_BAS_AERO_MAXIMA", "FUS" },
			{ "SPELL_BAS_OCULUS_TEMPEST", "OCULUS-TEMPEST" },
			{ "SPELL_BAS_UP_YOURS", "UP-YOURS" },
			{ "PLAYER_COMMAND_WITNESS_ME", "WITNESS-ME" },
			{ "PLAYER_COMMAND_BECOME_WIND", "LET-GO-YOUR-EARTHLY-TETHER-ENTER-THE-VOID-EMPTY-AND-BECOME-WIND" }
		};

		internal static ManualLogSource Log { get; private set; } = null;

		internal static Plugin Instance { get; private set; } = null;

		private static void PatchEnglishTxt()
		{
			string text = Path.Combine(Application.dataPath, "StreamingAssets", "Vosk", "Localisation", "english.txt");
			if (!File.Exists(text))
			{
				Log.LogWarning((object)("[SpellEditor] english.txt not found at " + text));
				return;
			}
			List<string> list = new List<string>(File.ReadAllLines(text));
			bool changed = false;
			foreach (KeyValuePair<string, string> requiredVoiceEntry in RequiredVoiceEntries)
			{
				string key = requiredVoiceEntry.Key;
				string value = requiredVoiceEntry.Value;
				string text2 = key + " :: " + value;
				bool flag = false;
				foreach (string item in list)
				{
					if (item.StartsWith(key + " ::"))
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					list.Add(text2);
					changed = true;
					Log.LogInfo((object)("[SpellEditor] Added voice entry: " + text2));
				}
			}
			SpellInterpreter.PatchEnglishTxt(list, ref changed);
			if (changed)
			{
				File.WriteAllLines(text, list);
			}
			else
			{
				Log.LogInfo((object)"[SpellEditor] english.txt already up to date.");
			}
		}

		private void Awake()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_010b: 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)
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			SpellInterpreter.Initialize(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "variants.json"));
			PatchEnglishTxt();
			new Harmony("com.local.yapyap.SpellEditor").PatchAll(Assembly.GetExecutingAssembly());
			FlightCommand.RegisterHandlers();
			WitnessCommand.RegisterHandlers();
			SpellVariants.RegisterTriggers();
			SpellInterpreter.RegisterHandlers();
			PrefabInjector.RegisterHandlers();
			VoiceInjector.SetOverride("PLAYER_COMMAND_BECOME_WIND", (SystemLanguage)10, VoiceInjector.ParseInput("LET-GO-YOUR-EARTHLY-TETHER-ENTER-THE-VOID-EMPTY-AND-BECOME-WIND"));
			VoiceInjector.SetOverride("SPELL_BAS_OCULUS_TEMPEST", (SystemLanguage)10, VoiceInjector.ParseInput("OCULUS-TEMPEST"));
			VoiceInjector.SetOverride("SPELL_BAS_FEATHER_FALL", (SystemLanguage)10, VoiceInjector.ParseInput("FEATHER-FALL"));
			VoiceInjector.SetOverride("SPELL_BAS_DOWN_DOG", (SystemLanguage)10, VoiceInjector.ParseInput("DOWN-DOG"));
			VoiceInjector.SetOverride("SPELL_BAS_AERO_MAXIMA", (SystemLanguage)10, VoiceInjector.ParseInput("FUS"));
			VoiceInjector.SetOverride("SPELL_BAS_UP_YOURS", (SystemLanguage)10, VoiceInjector.ParseInput("UP-YOURS"));
			VoiceInjector.SetOverride("PLAYER_COMMAND_WITNESS_ME", (SystemLanguage)10, VoiceInjector.ParseInput("WITNESS-ME"));
			GameObject val = new GameObject("SpellEditorRoot");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<SpellEditorWindow>();
			val.AddComponent<NetworkSync>();
			val.AddComponent<DummySpawner>();
			Log.LogInfo((object)"SpellEditor 1.1.0 loaded. Press F8 to open.");
		}
	}
	public static class PrefabInjector
	{
		[HarmonyPatch(typeof(UpdraftSpell), "Update")]
		public static class FeatherFallLandingPatch
		{
			public static void Postfix(UpdraftSpell __instance)
			{
				//IL_00d0: 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)
				if (!IsFeatherVariant(((Spell)__instance).SpellData?.voiceCommandKey) || !(_isUpdraftActiveField?.GetValue(__instance) is int num) || num == 0)
				{
					return;
				}
				object? obj = _casterPawnField?.GetValue(__instance);
				Pawn val = (Pawn)((obj is Pawn) ? obj : null);
				if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).isLocalPlayer)
				{
					return;
				}
				float num2 = ((_updraftStartTimeField?.GetValue(__instance) is float num3) ? num3 : 0f);
				if (!(Time.time - num2 < 3f))
				{
					object? obj2 = _getActiveRigidbodyMethod?.Invoke(__instance, null);
					Rigidbody val2 = (Rigidbody)((obj2 is Rigidbody) ? obj2 : null);
					if (!((Object)(object)val2 == (Object)null) && !(val2.linearVelocity.y > 0.5f) && Physics.Raycast(((Component)__instance).transform.position, Vector3.down, 2f))
					{
						_stopUpdraftMethod?.Invoke(__instance, null);
					}
				}
			}
		}

		[HarmonyPatch(typeof(VoiceSpell), "CollectHeldSpells")]
		public static class CollectHeldSpellsPatch
		{
			public static void Postfix(VoiceSpell __instance)
			{
				if (!(_allSpellsField?.GetValue(__instance) is List<Spell> allSpells))
				{
					return;
				}
				TryAdd(__instance, allSpells, (Spell?)(object)((IEnumerable<UpdraftSpell>)((Component)__instance).GetComponents<UpdraftSpell>()).FirstOrDefault((Func<UpdraftSpell, bool>)((UpdraftSpell u) => ((Spell)u).SpellData?.voiceCommandKey == "SPELL_BAS_FEATHER_FALL")));
				TryAdd(__instance, allSpells, (Spell?)(object)((IEnumerable<UpdraftSpell>)((Component)__instance).GetComponents<UpdraftSpell>()).FirstOrDefault((Func<UpdraftSpell, bool>)((UpdraftSpell u) => ((Spell)u).SpellData?.voiceCommandKey == "SPELL_BAS_DOWN_DOG")));
				TryAdd(__instance, allSpells, ((IEnumerable<Spell>)((Component)__instance).GetComponents<Spell>()).FirstOrDefault((Func<Spell, bool>)((Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_AERO_MAXIMA")));
				TryAdd(__instance, allSpells, ((IEnumerable<Spell>)((Component)__instance).GetComponents<Spell>()).FirstOrDefault((Func<Spell, bool>)((Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_OCULUS_TEMPEST")));
				TryAdd(__instance, allSpells, (Spell?)(object)((IEnumerable<UpdraftSpell>)((Component)__instance).GetComponents<UpdraftSpell>()).FirstOrDefault((Func<UpdraftSpell, bool>)((UpdraftSpell u) => ((Spell)u).SpellData?.voiceCommandKey == "SPELL_BAS_UP_YOURS")));
				foreach (SpellVariantDef variant in SpellInterpreter.GetAllVariants())
				{
					TryAdd(__instance, allSpells, ((IEnumerable<Spell>)((Component)__instance).GetComponents<Spell>()).FirstOrDefault((Func<Spell, bool>)((Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == variant.LocKey)));
				}
			}

			private static void TryAdd(VoiceSpell vs, List<Spell> allSpells, Spell? spell)
			{
				if ((Object)(object)spell == (Object)null || allSpells.Contains(spell))
				{
					return;
				}
				if (!spell.IsInitialized)
				{
					spell.Initialize(((Spell)vs).CasterIdentity);
					if (NetworkServer.active)
					{
						spell.SetWandHeld(true);
					}
				}
				allSpells.Add(spell);
				_sortSpells?.Invoke(vs, null);
			}
		}

		[HarmonyPatch(typeof(Spell), "CanCast")]
		public static class FeatherFallCanCastPatch
		{
			public static bool Prefix(Spell __instance, ref bool __result)
			{
				if (!IsFeatherVariant(__instance.SpellData?.voiceCommandKey))
				{
					return true;
				}
				UpdraftSpell val = FindParentUpDog((Component)(object)__instance);
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				__result = ((Spell)val).CanCast();
				return false;
			}
		}

		[HarmonyPatch(typeof(UpdraftSpell), "OnSpellActivate")]
		public static class FeatherFallActivatePatch
		{
			public static void Postfix(UpdraftSpell __instance)
			{
				if (IsFeatherVariant(((Spell)__instance).SpellData?.voiceCommandKey) && NetworkServer.active)
				{
					UpdraftSpell? obj = FindParentUpDog((Component)(object)__instance);
					if (obj != null)
					{
						((Spell)obj).SetCastData();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Spell), "OnSpellDeactivate")]
		public static class FeatherFallDeactivatePatch
		{
			public static void Postfix(Spell __instance)
			{
				if (IsFeatherVariant(__instance.SpellData?.voiceCommandKey) && NetworkServer.active)
				{
					UpdraftSpell? obj = FindParentUpDog((Component)(object)__instance);
					if (obj != null)
					{
						((Spell)obj).OnSpellDeactivate();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Spell), "CanCast")]
		public static class UpYoursCanCastPatch
		{
			public static bool Prefix(Spell __instance, ref bool __result)
			{
				if (__instance.SpellData?.voiceCommandKey != "SPELL_BAS_UP_YOURS")
				{
					return true;
				}
				UpdraftSpell val = FindParentUpDog((Component)(object)__instance);
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				__result = ((Spell)val).CanCast();
				return false;
			}
		}

		[HarmonyPatch(typeof(UpdraftSpell), "OnSpellActivate")]
		public static class UpYoursActivatePatch
		{
			public static bool Prefix(UpdraftSpell __instance)
			{
				if (((Spell)__instance).SpellData?.voiceCommandKey != "SPELL_BAS_UP_YOURS")
				{
					return true;
				}
				if (!NetworkServer.active)
				{
					return false;
				}
				object? obj = _casterPawnField?.GetValue(__instance);
				Pawn val = (Pawn)((obj is Pawn) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				Pawn val2 = FindUpYoursTarget(val);
				if ((Object)(object)val2 == (Object)null)
				{
					return false;
				}
				UpdraftSpell? obj2 = FindParentUpDog((Component)(object)__instance);
				if (obj2 != null)
				{
					((Spell)obj2).SetCastData();
				}
				ApplyUpdraftToTarget(val2);
				return false;
			}
		}

		[HarmonyPatch(typeof(Spell), "CanCast")]
		public static class AeroMaximaCanCastPatch
		{
			public static bool Prefix(Spell __instance, ref bool __result)
			{
				if (__instance.SpellData?.voiceCommandKey != "SPELL_BAS_AERO_MAXIMA")
				{
					return true;
				}
				Spell val = FindParentAero((Component)(object)__instance);
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				__result = val.CanCast() && val.CurrentCharges >= 2;
				return false;
			}
		}

		[HarmonyPatch(typeof(Spell), "OnSpellActivate")]
		public static class AeroMaximaActivatePatch
		{
			public static void Postfix(Spell __instance)
			{
				if (__instance.SpellData?.voiceCommandKey != "SPELL_BAS_AERO_MAXIMA" || !NetworkServer.active)
				{
					return;
				}
				Spell val = FindParentAero((Component)(object)__instance);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				val.SetCastData();
				val.SetCastData();
				if (!(Time.time - _lastYellTime < 1f))
				{
					_lastYellTime = Time.time;
					object? obj = _casterPawnField?.GetValue(__instance);
					Pawn val2 = (Pawn)((obj is Pawn) ? obj : null);
					if (!((Object)(object)val2 == (Object)null))
					{
						object obj2 = _pawnEmotesEmoteStateField?.GetValue(val2.Emotes);
						_emotePlayMethod?.Invoke(obj2, new object[2] { _yellEmoteHash, 1.5f });
					}
				}
			}
		}

		[HarmonyPatch(typeof(Spell), "OnSpellDeactivate")]
		public static class AeroMaximaDeactivatePatch
		{
			public static void Postfix(Spell __instance)
			{
				if (!(__instance.SpellData?.voiceCommandKey != "SPELL_BAS_AERO_MAXIMA") && NetworkServer.active)
				{
					Spell? obj = FindParentAero((Component)(object)__instance);
					if (obj != null)
					{
						obj.OnSpellDeactivate();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Spell), "CanCast")]
		public static class OculusTempestCanCastPatch
		{
			public static bool Prefix(Spell __instance, ref bool __result)
			{
				if (__instance.SpellData?.voiceCommandKey != "SPELL_BAS_OCULUS_TEMPEST")
				{
					return true;
				}
				Spell val = FindParentTempest((Component)(object)__instance);
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				__result = val.CanCast();
				return false;
			}
		}

		[HarmonyPatch(typeof(Spell), "OnSpellActivate")]
		public static class OculusTempestActivatePatch
		{
			public static void Postfix(Spell __instance)
			{
				if (!(__instance.SpellData?.voiceCommandKey != "SPELL_BAS_OCULUS_TEMPEST") && NetworkServer.active)
				{
					Spell? obj = FindParentTempest((Component)(object)__instance);
					if (obj != null)
					{
						obj.SetCastData();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Spell), "OnSpellDeactivate")]
		public static class OculusTempestDeactivatePatch
		{
			public static void Postfix(Spell __instance)
			{
				if (!(__instance.SpellData?.voiceCommandKey != "SPELL_BAS_OCULUS_TEMPEST") && NetworkServer.active)
				{
					Spell? obj = FindParentTempest((Component)(object)__instance);
					if (obj != null)
					{
						obj.OnSpellDeactivate();
					}
				}
			}
		}

		[HarmonyPatch(typeof(NetworkManager), "OnStartServer")]
		public static class OnStartServerPatch
		{
			public static void Postfix()
			{
				Inject();
			}
		}

		[HarmonyPatch(typeof(NetworkManager), "OnStartClient")]
		public static class OnStartClientPatch
		{
			public static void Postfix()
			{
				Inject();
			}
		}

		private static bool _done;

		private static readonly BindingFlags BF = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly FieldInfo _spellDataField = typeof(Spell).GetField("spellData", BF);

		private static readonly FieldInfo _isSecretField = typeof(Spell).GetField("isSecret", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo _allSpellsField = typeof(VoiceSpell).GetField("allSpells", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly MethodInfo _sortSpells = typeof(VoiceSpell).GetMethod("SortSpells", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo _isUpdraftActiveField = typeof(UpdraftSpell).GetField("isUpdraftActive", BF);

		private static readonly FieldInfo _updraftStartTimeField = typeof(UpdraftSpell).GetField("updraftStartTime", BF);

		private static readonly FieldInfo _casterPawnField = typeof(Spell).GetField("casterPawn", BF);

		private static readonly MethodInfo _stopUpdraftMethod = typeof(UpdraftSpell).GetMethod("StopUpdraft", BF);

		private static readonly MethodInfo _getActiveRigidbodyMethod = typeof(UpdraftSpell).GetMethod("GetActiveRigidbody", BF);

		private static readonly MethodInfo _targetRpcActivateMethod = typeof(UpdraftSpell).GetMethod("TargetRpcSpellActivate", BF);

		private const float FeatherFallGracePeriod = 3f;

		private const float FeatherFallLandingRayDist = 2f;

		private static readonly int _yellEmoteHash = Animator.StringToHash("Emote_Yell");

		private static float _lastYellTime = -999f;

		private static readonly FieldInfo? _pawnEmotesEmoteStateField = typeof(PawnEmotes).GetField("emoteState", BF);

		private static readonly MethodInfo? _emotePlayMethod = typeof(ControllerStateEmote).GetMethod("PlayEmote", BF, null, new Type[2]
		{
			typeof(int),
			typeof(float)
		}, null);

		private static bool IsFeatherVariant(string? key)
		{
			if (!(key == "SPELL_BAS_FEATHER_FALL"))
			{
				return key == "SPELL_BAS_DOWN_DOG";
			}
			return true;
		}

		private static UpdraftSpell? FindParentUpDog(Component feather)
		{
			return Array.Find(feather.GetComponents<UpdraftSpell>(), (UpdraftSpell u) => ((Spell)u).SpellData?.voiceCommandKey == "SPELL_BAS_UPDOG");
		}

		private static Pawn? FindUpYoursTarget(Pawn caster)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			Vector3 lookOrigin = caster.LookOrigin;
			Vector3 aimDirection = caster.AimDirection;
			float num = 20f;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(lookOrigin, aimDirection, ref val, num))
			{
				num = ((RaycastHit)(ref val)).distance;
			}
			RaycastHit[] array = Physics.SphereCastAll(lookOrigin, 0.5f, aimDirection, num, -1, (QueryTriggerInteraction)1);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit[] array2 = array;
			Pawn val4 = default(Pawn);
			for (int num2 = 0; num2 < array2.Length; num2++)
			{
				RaycastHit val2 = array2[num2];
				if (!((Component)((RaycastHit)(ref val2)).collider).CompareTag("IgnoreCollision") && !((Component)((RaycastHit)(ref val2)).collider).transform.IsChildOf(((Component)caster).transform))
				{
					NetworkIdentity val3 = ((Component)((RaycastHit)(ref val2)).collider).GetComponent<NetworkIdentity>() ?? ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<NetworkIdentity>();
					if (!((Object)(object)val3 == (Object)null) && ((Component)val3).TryGetComponent<Pawn>(ref val4) && !((Object)(object)val4 == (Object)(object)caster))
					{
						return val4;
					}
				}
			}
			return null;
		}

		private static void ApplyUpdraftToTarget(Pawn target)
		{
			UpdraftSpell val = FindUpdraftOnPawn(target, "SPELL_BAS_UPDOG");
			if ((Object)(object)val != (Object)null && ((NetworkBehaviour)target).connectionToClient != null)
			{
				val.NetworksyncedUpdraftActive = true;
				_targetRpcActivateMethod?.Invoke(val, new object[1] { ((NetworkBehaviour)target).connectionToClient });
				return;
			}
			PawnControllerStateMachine controllerStateMachine = target.ControllerStateMachine;
			Rigidbody val2 = ((controllerStateMachine != null) ? controllerStateMachine.Rigidbody : null);
			if ((Object)(object)val2 != (Object)null && !val2.isKinematic)
			{
				((Component)target).gameObject.AddComponent<UpdraftApplicator>().Initialize(val2);
			}
		}

		private static UpdraftSpell? FindUpdraftOnPawn(Pawn pawn, string spellKey)
		{
			NetworkPuppetProp networkCurrentRightHandNetworkProp = pawn.PropInteractions.NetworkCurrentRightHandNetworkProp;
			NetworkPuppetProp networkCurrentLeftHandNetworkProp = pawn.PropInteractions.NetworkCurrentLeftHandNetworkProp;
			return FindByKey(networkCurrentRightHandNetworkProp, spellKey) ?? FindByKey(networkCurrentLeftHandNetworkProp, spellKey);
			static UpdraftSpell? FindByKey(NetworkPuppetProp? prop, string key)
			{
				if (!((Object)(object)prop == (Object)null))
				{
					return Array.Find(((Component)prop).GetComponents<UpdraftSpell>(), (UpdraftSpell u) => ((u == null) ? null : ((Spell)u).SpellData?.voiceCommandKey) == key);
				}
				return null;
			}
		}

		private static void InjectUpYours(NetworkPuppetWandProp wand)
		{
			if (!Array.Exists(((Component)wand).GetComponents<Spell>(), (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_UP_YOURS"))
			{
				UpdraftSpell val = Array.Find(((Component)wand).GetComponents<UpdraftSpell>(), (UpdraftSpell u) => ((u == null) ? null : ((Spell)u).SpellData?.voiceCommandKey) == "SPELL_BAS_UPDOG");
				if ((Object)(object)((val != null) ? ((Spell)val).SpellData : null) == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[PrefabInjector] Up-Yours: source UPDOG spell missing.");
					return;
				}
				SpellData val2 = SpellRegistry.Clone(((Spell)val).SpellData, "UP-YOURS");
				SetSdField(val2, "voiceCommandKey", "SPELL_BAS_UP_YOURS");
				UpdraftSpell val3 = ((Component)wand).gameObject.AddComponent<UpdraftSpell>();
				CopySerializedFields(typeof(UpdraftSpell), val, val3);
				_spellDataField?.SetValue(val3, val2);
				_isSecretField?.SetValue(val3, true);
				((Behaviour)val3).enabled = true;
				Plugin.Log.LogInfo((object)"[PrefabInjector] Up-Yours added.");
			}
		}

		public static void RegisterHandlers()
		{
		}

		private static Spell? FindParentAero(Component variant)
		{
			return Array.Find(variant.GetComponents<Spell>(), (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_VENTO");
		}

		private static Spell? FindParentTempest(Component variant)
		{
			return Array.Find(variant.GetComponents<Spell>(), (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_TEMPEST");
		}

		public static void Inject()
		{
			if (!_done)
			{
				NetworkPuppetWandProp val = FindWandPrefab();
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[PrefabInjector] PropWandOfBasics prefab not found.");
					return;
				}
				InjectFeatherFall(val);
				InjectDownDog(val);
				InjectAeroMaxima(val);
				InjectOculusTempest(val);
				InjectUpYours(val);
				InjectDataDrivenVariants(val);
				_done = true;
			}
		}

		private static void InjectFeatherFall(NetworkPuppetWandProp wand)
		{
			UpdraftSpell[] components = ((Component)wand).GetComponents<UpdraftSpell>();
			if (components.Length < 2)
			{
				UpdraftSpell val = components.FirstOrDefault();
				if ((Object)(object)((val != null) ? ((Spell)val).SpellData : null) == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[PrefabInjector] Feather-Fall: source UpdraftSpell missing.");
					return;
				}
				SpellData val2 = SpellRegistry.Clone(((Spell)val).SpellData, "FEATHER-FALL");
				SetSdField(val2, "voiceCommandKey", "SPELL_BAS_FEATHER_FALL");
				UpdraftSpell val3 = ((Component)wand).gameObject.AddComponent<UpdraftSpell>();
				CopySerializedFields(typeof(UpdraftSpell), val, val3);
				_spellDataField?.SetValue(val3, val2);
				_isSecretField?.SetValue(val3, true);
				SetCompField((Component)(object)val3, "initialUpwardForce", 0f);
				SetCompField((Component)(object)val3, "continuousUpwardForce", 0f);
				SetCompField((Component)(object)val3, "fallSlowMultiplier", 0.88f);
				SetCompField((Component)(object)val3, "duration", 10f);
				((Behaviour)val3).enabled = true;
				Plugin.Log.LogInfo((object)"[PrefabInjector] Feather-Fall added.");
			}
		}

		private static void InjectDownDog(NetworkPuppetWandProp wand)
		{
			if (!Array.Exists(((Component)wand).GetComponents<Spell>(), (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_DOWN_DOG"))
			{
				UpdraftSpell val = Array.Find(((Component)wand).GetComponents<UpdraftSpell>(), (UpdraftSpell u) => ((u == null) ? null : ((Spell)u).SpellData?.voiceCommandKey) == "SPELL_BAS_FEATHER_FALL");
				if ((Object)(object)((val != null) ? ((Spell)val).SpellData : null) == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[PrefabInjector] Down-Dog: source Feather-Fall spell missing.");
					return;
				}
				SpellData val2 = SpellRegistry.Clone(((Spell)val).SpellData, "DOWN-DOG");
				SetSdField(val2, "voiceCommandKey", "SPELL_BAS_DOWN_DOG");
				UpdraftSpell val3 = ((Component)wand).gameObject.AddComponent<UpdraftSpell>();
				CopySerializedFields(typeof(UpdraftSpell), val, val3);
				_spellDataField?.SetValue(val3, val2);
				_isSecretField?.SetValue(val3, true);
				((Behaviour)val3).enabled = true;
				Plugin.Log.LogInfo((object)"[PrefabInjector] Down-Dog added.");
			}
		}

		private static void InjectOculusTempest(NetworkPuppetWandProp wand)
		{
			Spell[] components = ((Component)wand).GetComponents<Spell>();
			if (Array.Exists(components, (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_OCULUS_TEMPEST"))
			{
				return;
			}
			Spell val = Array.Find(components, (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_TEMPEST");
			if ((Object)(object)((val != null) ? val.SpellData : null) == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[PrefabInjector] Oculus-Tempest: source Tempest spell missing.");
				return;
			}
			SpellData val2 = SpellRegistry.Clone(val.SpellData, "OCULUS-TEMPEST");
			SetSdField(val2, "voiceCommandKey", "SPELL_BAS_OCULUS_TEMPEST");
			GameObject val3 = CloneOculusProjectile(val.SpellData.objectToSpawnPrefab);
			if ((Object)(object)val3 != (Object)null)
			{
				SetSdField(val2, "objectToSpawnPrefab", val3);
			}
			Component obj = ((Component)wand).gameObject.AddComponent(((object)val).GetType());
			Spell val4 = (Spell)(object)((obj is Spell) ? obj : null);
			if ((Object)(object)val4 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[PrefabInjector] Oculus-Tempest: AddComponent failed.");
				return;
			}
			CopySerializedFields(((object)val).GetType(), val, val4);
			_spellDataField?.SetValue(val4, val2);
			_isSecretField?.SetValue(val4, true);
			((Behaviour)val4).enabled = true;
			Plugin.Log.LogInfo((object)"[PrefabInjector] Oculus-Tempest added.");
		}

		private static GameObject? CloneOculusProjectile(GameObject? original)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			if ((Object)(object)original == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("OculusTempestProjectileContainer");
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			GameObject obj = Object.Instantiate<GameObject>(original, val.transform);
			OculusTempestVariant.RegisterProjectilePrefab(obj);
			return obj;
		}

		private static void InjectAeroMaxima(NetworkPuppetWandProp wand)
		{
			Spell[] components = ((Component)wand).GetComponents<Spell>();
			if (Array.Exists(components, (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_AERO_MAXIMA"))
			{
				return;
			}
			Spell val = Array.Find(components, (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == "SPELL_BAS_VENTO");
			if ((Object)(object)((val != null) ? val.SpellData : null) == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[PrefabInjector] Aero-Maxima: source Aero spell missing.");
				return;
			}
			SpellData val2 = SpellRegistry.Clone(val.SpellData, "AERO-MAXIMA");
			SetSdField(val2, "voiceCommandKey", "SPELL_BAS_AERO_MAXIMA");
			GameObject val3 = CloneProjectilePrefab(val.SpellData.objectToSpawnPrefab);
			if ((Object)(object)val3 != (Object)null)
			{
				SetSdField(val2, "objectToSpawnPrefab", val3);
			}
			Component obj = ((Component)wand).gameObject.AddComponent(((object)val).GetType());
			Spell val4 = (Spell)(object)((obj is Spell) ? obj : null);
			if ((Object)(object)val4 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[PrefabInjector] Aero-Maxima: AddComponent failed.");
				return;
			}
			CopySerializedFields(((object)val).GetType(), val, val4);
			_spellDataField?.SetValue(val4, val2);
			_isSecretField?.SetValue(val4, true);
			((Behaviour)val4).enabled = true;
			Plugin.Log.LogInfo((object)"[PrefabInjector] Aero-Maxima added.");
		}

		private static GameObject? CloneProjectilePrefab(GameObject? original)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_003b: 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)
			if ((Object)(object)original == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("AeroMaximaProjectileContainer");
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			GameObject obj = Object.Instantiate<GameObject>(original, val.transform);
			obj.transform.localScale = original.transform.localScale * Mathf.Pow(2f, 1f / 3f);
			ProjectilePush component = obj.GetComponent<ProjectilePush>();
			if ((Object)(object)component != (Object)null)
			{
				float num = ((typeof(ProjectilePush).GetField("pushForce", BF)?.GetValue(component) is float num2) ? num2 : 10f);
				SetCompField((Component)(object)component, "pushForce", num * 2f);
				float num3 = ((BaseProjectile)component).ProjectileData?.maxTravelDistance ?? 30f;
				SetCompField((Component)(object)component, "maxTravelDistanceOverride", num3 * Mathf.Pow(2f, 1f / 3f));
				return obj;
			}
			Plugin.Log.LogWarning((object)"[PrefabInjector] Aero-Maxima: ProjectilePush not found on clone.");
			return obj;
		}

		private static void InjectDataDrivenVariants(NetworkPuppetWandProp wand)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			Spell[] components = ((Component)wand).GetComponents<Spell>();
			foreach (SpellVariantDef variant in SpellInterpreter.GetAllVariants())
			{
				if (!Array.Exists(components, (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == variant.LocKey))
				{
					Spell val = Array.Find(components, (Spell s) => ((s == null) ? null : s.SpellData?.voiceCommandKey) == variant.BaseSpellKey);
					if ((Object)(object)((val != null) ? val.SpellData : null) == (Object)null)
					{
						Plugin.Log.LogWarning((object)("[PrefabInjector] Variant '" + variant.LocKey + "': base spell '" + variant.BaseSpellKey + "' not found."));
					}
					else
					{
						SpellData val2 = SpellRegistry.Clone(val.SpellData, variant.VoiceCommand);
						SetSdField(val2, "voiceCommandKey", variant.LocKey);
						Spell val3 = (Spell)((Component)wand).gameObject.AddComponent(((object)val).GetType());
						CopySerializedFields(((object)val).GetType(), val, val3);
						_spellDataField?.SetValue(val3, val2);
						_isSecretField?.SetValue(val3, true);
						((Behaviour)val3).enabled = true;
						Plugin.Log.LogInfo((object)("[PrefabInjector] Injected data-driven variant: " + variant.LocKey));
					}
				}
			}
		}

		private static void CopySerializedFields(Type type, object source, object dest)
		{
			FieldInfo[] fields = type.GetFields(BF);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!fieldInfo.IsStatic && (fieldInfo.IsPublic || fieldInfo.GetCustomAttributes(typeof(SerializeField), inherit: true).Length != 0))
				{
					fieldInfo.SetValue(dest, fieldInfo.GetValue(source));
				}
			}
		}

		private static NetworkPuppetWandProp? FindWandPrefab()
		{
			return Array.Find(Resources.FindObjectsOfTypeAll<NetworkPuppetWandProp>(), delegate(NetworkPuppetWandProp w)
			{
				//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)
				if (((Object)w).name == "PropWandOfBasics")
				{
					Scene scene = ((Component)w).gameObject.scene;
					return !((Scene)(ref scene)).IsValid();
				}
				return false;
			});
		}

		private static void SetSdField(SpellData sd, string name, object value)
		{
			typeof(SpellData).GetField(name, BF)?.SetValue(sd, value);
		}

		private static void SetCompField(Component comp, string name, object value)
		{
			((object)comp).GetType().GetField(name, BF)?.SetValue(comp, value);
		}

		private static T GetCompField<T>(Component comp, string name, T fallback)
		{
			object obj = ((object)comp).GetType().GetField(name, BF)?.GetValue(comp);
			if (obj is T)
			{
				return (T)obj;
			}
			return fallback;
		}
	}
	public class UpdraftApplicator : MonoBehaviour
	{
		private Rigidbody _rb;

		private float _elapsed;

		private const float InitialForce = 750f;

		private const float ContinuousForce = 200f;

		private const float FallSlowFactor = 0.3f;

		private const float MaxVelocity = 15f;

		private const float Duration = 5f;

		public void Initialize(Rigidbody rb)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			_rb = rb;
			rb.AddForce(Vector3.up * 750f, (ForceMode)1);
		}

		private void Update()
		{
			//IL_0041: 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_0047: 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_006a: 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_00b0: 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_008f: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_rb == (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			_elapsed += Time.deltaTime;
			if (_elapsed >= 5f)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Vector3 linearVelocity = _rb.linearVelocity;
			if (linearVelocity.y < 0f)
			{
				linearVelocity.y *= 0.3f;
				_rb.linearVelocity = linearVelocity;
			}
			else if (linearVelocity.y < 15f)
			{
				_rb.AddForce(Vector3.up * 200f * Time.deltaTime, (ForceMode)0);
			}
			linearVelocity = _rb.linearVelocity;
			if (linearVelocity.y > 15f)
			{
				linearVelocity.y = 15f;
				_rb.linearVelocity = linearVelocity;
			}
		}
	}
	public class SpellEditorWindow : MonoBehaviour
	{
		private bool _visible;

		private Rect _windowRect = new Rect(20f, 20f, 1200f, 700f);

		private bool _selectedIsVariant;

		private int _selectedNode;

		private Vector2 _nodeScroll;

		private string _search = "";

		private string _schoolFilter = "ALL";

		private Vector2 _listScroll;

		private int _selectedIndex = -1;

		private List<SpellData> _allSpells = new List<SpellData>();

		private List<SpellData> _filtered = new List<SpellData>();

		private Dictionary<string, string> _keyTriggers = new Dictionary<string, string>();

		private List<(FieldInfo field, string draft, string live)> _chargeFields = new List<(FieldInfo, string, string)>();

		private string _editKey = "";

		private string _editTrigger = "";

		private List<SpellVariantDef> _variants = new List<SpellVariantDef>();

		private int _selVariant = -1;

		private Vector2 _variantDetailScroll;

		private bool _wizardActive;

		private int _wizardStep;

		private string _newLocKey = "SPELL_CUSTOM_";

		private string _newBaseKey = "";

		private string _newVoiceCmd = "";

		private SpellVariantDef _wizardDef = new SpellVariantDef
		{
			Gate = new GateDef(),
			Targeting = new TargetingDef()
		};

		private string _wizardRadius = "0.50";

		private string _wizardMaxDist = "20.0";

		private string _wizardError = "";

		private string _draftRadius = "";

		private string _draftMaxDist = "";

		private string _draftMinCharges = "";

		private bool _addingEffect;

		private int _addEffectTypeIdx;

		private string _addEffectSpellKey = "";

		private string[] _variantErrors = Array.Empty<string>();

		private static readonly Dictionary<string, Color32> Schools = new Dictionary<string, Color32>
		{
			["ARC"] = new Color32((byte)153, (byte)102, (byte)230, byte.MaxValue),
			["BAS"] = new Color32((byte)102, (byte)204, (byte)102, byte.MaxValue),
			["BLS"] = new Color32((byte)230, (byte)204, (byte)76, byte.MaxValue),
			["FIR"] = new Color32((byte)230, (byte)102, (byte)51, byte.MaxValue),
			["GRS"] = new Color32((byte)179, (byte)230, (byte)51, byte.MaxValue),
			["ICE"] = new Color32((byte)102, (byte)204, (byte)230, byte.MaxValue),
			["ILU"] = new Color32((byte)230, (byte)102, (byte)179, byte.MaxValue),
			["TEL"] = new Color32((byte)230, (byte)153, (byte)51, byte.MaxValue),
			["WIP"] = new Color32((byte)153, (byte)153, (byte)153, byte.MaxValue)
		};

		private static readonly string[] SchoolKeys = new string[10] { "ALL", "ARC", "BAS", "BLS", "FIR", "GRS", "ICE", "ILU", "TEL", "WIP" };

		private static readonly HashSet<string> ChargeFieldNames = new HashSet<string> { "cooldown", "charges", "chargePerCast", "chargeCostPerSecondCast", "regenInterval", "regenPerInterval", "regenDelay" };

		private static readonly string[] NodeNames = new string[5] { "Voice", "Charges", "Activation", "Targeting", "Effects" };

		private bool _stylesReady;

		private GUIStyle _winStyle;

		private GUIStyle _header;

		private GUIStyle _subLabel;

		private GUIStyle _fieldVal;

		private GUIStyle _tab;

		private GUIStyle _tabActive;

		private GUIStyle _row;

		private GUIStyle _rowSel;

		private GUIStyle _nodeBtn;

		private GUIStyle _nodeBtnSel;

		private Texture2D _txDark;

		private Texture2D _txPanel;

		private Texture2D _txSel;

		private Texture2D _txBtn;

		private Texture2D _txBtnHov;

		private CursorLockMode _savedLockState;

		private bool _savedCursorVisible;

		private static readonly string[] WizardStepNames = new string[5] { "Identity", "Gate", "Targeting", "Effects", "Review" };

		private void Update()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown((KeyCode)289))
			{
				_visible = !_visible;
				if (_visible)
				{
					_savedLockState = Cursor.lockState;
					_savedCursorVisible = Cursor.visible;
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
					Refresh();
				}
				else
				{
					Cursor.lockState = _savedLockState;
					Cursor.visible = _savedCursorVisible;
				}
			}
		}

		private void OnGUI()
		{
			//IL_0026: 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_004c: Expected O, but got Unknown
			//IL_0047: 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)
			if (_visible)
			{
				EnsureStyles();
				GUI.skin.label.richText = true;
				_windowRect = GUILayout.Window(47001, _windowRect, new WindowFunction(DrawWindow), "", _winStyle, Array.Empty<GUILayoutOption>());
			}
		}

		private void Refresh()
		{
			SpellRegistry.Refresh();
			WandRegistry.Refresh();
			_keyTriggers = VoiceInjector.GetAllKeysWithTriggers((SystemLanguage)10).ToDictionary<(string, string), string, string>(((string key, string trigger) e) => e.key, ((string key, string trigger) e) => e.trigger);
			_variants = SpellInterpreter.GetAllVariants().ToList();
			HashSet<string> variantKeys = new HashSet<string>(_variants.Select((SpellVariantDef v) => v.LocKey));
			_allSpells = SpellRegistry.All.Where((SpellData s) => !string.IsNullOrEmpty(s.voiceCommandKey) && !variantKeys.Contains(s.voiceCommandKey)).ToList();
			ApplyFilter();
			if (_selectedIndex >= _filtered.Count)
			{
				SelectSpell(-1);
			}
			else if (_selectedIndex >= 0 && !_selectedIsVariant)
			{
				LoadChargeFields(_filtered[_selectedIndex]);
			}
			if (_selVariant >= _variants.Count)
			{
				SelectVariant(-1);
			}
		}

		private void ApplyFilter()
		{
			_filtered = _allSpells.Where(delegate(SpellData s)
			{
				bool num = _schoolFilter == "ALL" || (s.voiceCommandKey?.Contains("_" + _schoolFilter + "_") ?? false);
				int num2;
				if (!string.IsNullOrEmpty(_search))
				{
					string spellName = s.spellName;
					if (spellName == null || spellName.IndexOf(_search, StringComparison.OrdinalIgnoreCase) < 0)
					{
						string voiceCommandKey = s.voiceCommandKey;
						num2 = ((voiceCommandKey != null && voiceCommandKey.IndexOf(_search, StringComparison.OrdinalIgnoreCase) >= 0) ? 1 : 0);
						goto IL_008c;
					}
				}
				num2 = 1;
				goto IL_008c;
				IL_008c:
				bool flag = (byte)num2 != 0;
				return num && flag;
			}).ToList();
			if (_selectedIndex >= _filtered.Count)
			{
				SelectSpell(-1);
			}
		}

		private void SelectSpell(int index)
		{
			//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)
			_selectedIndex = index;
			_selectedIsVariant = false;
			_selectedNode = 0;
			_nodeScroll = Vector2.zero;
			_selVariant = -1;
			if (index < 0 || index >= _filtered.Count)
			{
				_chargeFields = new List<(FieldInfo, string, string)>();
				_editKey = (_editTrigger = "");
				return;
			}
			SpellData val = _filtered[index];
			_editKey = val.voiceCommandKey ?? "";
			_editTrigger = (_keyTriggers.TryGetValue(_editKey, out string value) ? value : "");
			LoadChargeFields(val);
		}

		private void SelectVariant(int i)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			_selVariant = i;
			if (i >= 0)
			{
				_selectedIsVariant = true;
				_selectedIndex = -1;
				_selectedNode = 0;
			}
			else
			{
				_selectedIsVariant = false;
			}
			_nodeScroll = Vector2.zero;
			_variantDetailScroll = Vector2.zero;
			_variantErrors = Array.Empty<string>();
			_addingEffect = false;
			if (i < 0 || i >= _variants.Count)
			{
				_draftRadius = (_draftMaxDist = (_draftMinCharges = ""));
				return;
			}
			SpellVariantDef spellVariantDef = _variants[i];
			_draftRadius = spellVariantDef.Targeting?.Radius.ToString("F2") ?? "0.50";
			_draftMaxDist = spellVariantDef.Targeting?.MaxDistance.ToString("F1") ?? "20.0";
			_draftMinCharges = spellVariantDef.Gate?.MinCharges.ToString() ?? "1";
		}

		private void LoadChargeFields(SpellData sd)
		{
			_chargeFields = (from f in typeof(SpellData).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where ChargeFieldNames.Contains(f.Name) && IsEditable(f.FieldType)
				select f).Select(delegate(FieldInfo f)
			{
				string text = f.GetValue(sd)?.ToString() ?? "";
				return (f: f, text, text);
			}).ToList();
		}

		private void ApplyChargeFields(SpellData sd)
		{
			foreach (var (fieldInfo, text, _) in _chargeFields)
			{
				try
				{
					object obj = ParseValue(fieldInfo.FieldType, text);
					if (obj != null)
					{
						fieldInfo.SetValue(sd, obj);
					}
				}
				catch
				{
					Plugin.Log.LogWarning((object)("[SpellEditor] Could not parse '" + text + "' for '" + fieldInfo.Name + "'."));
				}
			}
			Plugin.Log.LogInfo((object)("[SpellEditor] Charge fields applied to '" + sd.spellName + "'."));
		}

		private void DrawWindow(int id)
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("<b>SpellForge</b>  <size=10><color=#777>v2.0  ·  F8 to toggle</color></size>", _header, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUILayout.Label($"<size=10><color=#555>{SpellRegistry.All.Count} spells  ·  {WandRegistry.All.Count} wands  ·  {_variants.Count} variants</color></size>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			if (GUILayout.Button("Refresh", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				Refresh();
			}
			GUILayout.EndHorizontal();
			DrawSeparator();
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(260f) });
			DrawSpellList();
			GUILayout.EndVertical();
			GUILayout.Space(10f);
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			DrawPipelineView();
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, 30f));
		}

		private void DrawSpellList()
		{
			//IL_0145: 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_015e: 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_00a4: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			string text = GUILayout.TextField(_search, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			if (text != _search)
			{
				_search = text;
				ApplyFilter();
			}
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			string[] schoolKeys = SchoolKeys;
			foreach (string text2 in schoolKeys)
			{
				Color32 value;
				? val = ((!(_schoolFilter == text2)) ? new Color32((byte)50, (byte)50, (byte)58, byte.MaxValue) : (Schools.TryGetValue(text2, out value) ? value : new Color32((byte)80, (byte)120, (byte)220, byte.MaxValue)));
				Color backgroundColor = GUI.backgroundColor;
				GUI.backgroundColor = Color32.op_Implicit((Color32)val);
				string text3 = text2;
				GUIStyle tab = _tab;
				bool flag = ((text2 == "ALL" || text2 == "ICE") ? true : false);
				if (GUILayout.Button(text3, tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width((float)(flag ? 34 : 30)) }))
				{
					_schoolFilter = text2;
					ApplyFilter();
				}
				GUI.backgroundColor = backgroundColor;
			}
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			DrawSeparator();
			_listScroll = GUILayout.BeginScrollView(_listScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			GUILayout.Label($"<size=9><color=#666>BASE SPELLS  {_filtered.Count}</color></size>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(2f);
			for (int j = 0; j < _filtered.Count; j++)
			{
				SpellData val2 = _filtered[j];
				string school = GetSchool(val2.voiceCommandKey);
				string value2;
				string text4 = (_keyTriggers.TryGetValue(val2.voiceCommandKey ?? "", out value2) ? value2 : "?");
				Color32 value3;
				string text5 = (Schools.TryGetValue(school, out value3) ? $"#{value3.r:X2}{value3.g:X2}{value3.b:X2}" : "#888");
				if (GUILayout.Button("<color=" + text5 + ">◆</color>  <b>" + val2.spellName + "</b>\n<size=10><color=#888>" + text4 + "</color></size>", (!_selectedIsVariant && j == _selectedIndex) ? _rowSel : _row, Array.Empty<GUILayoutOption>()))
				{
					SelectSpell(j);
				}
			}
			GUILayout.Space(8f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"<size=9><color=#666>VARIANTS  {_variants.Count}</color></size>", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			if (GUILayout.Button(_wizardActive ? "✕" : "+", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) }))
			{
				if (_wizardActive)
				{
					CancelWizard();
				}
				else
				{
					StartWizard();
				}
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(2f);
			for (int k = 0; k < _variants.Count; k++)
			{
				SpellVariantDef spellVariantDef = _variants[k];
				if (string.IsNullOrEmpty(_search) || spellVariantDef.VoiceCommand.IndexOf(_search, StringComparison.OrdinalIgnoreCase) >= 0 || spellVariantDef.LocKey.IndexOf(_search, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					bool flag2 = _selectedIsVariant && k == _selVariant;
					if (GUILayout.Button("<color=#4080ff>⬡</color>  <b>" + spellVariantDef.VoiceCommand + "</b>\n<size=10><color=#888>" + spellVariantDef.LocKey + "</color></size>", flag2 ? _rowSel : _row, Array.Empty<GUILayoutOption>()))
					{
						SelectVariant(k);
					}
				}
			}
			GUILayout.EndScrollView();
		}

		private void DrawPipelineView()
		{
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: 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_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: 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_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			if (_wizardActive)
			{
				DrawWizard();
				return;
			}
			bool flag = !_selectedIsVariant && _selectedIndex >= 0 && _selectedIndex < _filtered.Count;
			bool flag2 = _selectedIsVariant && _selVariant >= 0 && _selVariant < _variants.Count;
			if (!flag && !flag2)
			{
				GUILayout.FlexibleSpace();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				GUILayout.Label("<color=#444>← select a spell or variant</color>", _subLabel, Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				GUILayout.EndHorizontal();
				GUILayout.FlexibleSpace();
				return;
			}
			if (flag)
			{
				SpellData val = _filtered[_selectedIndex];
				string school = GetSchool(val.voiceCommandKey);
				Color32 value;
				string text = (Schools.TryGetValue(school, out value) ? $"#{value.r:X2}{value.g:X2}{value.b:X2}" : "#888");
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("<b><size=15>" + val.spellName + "</size></b>  <color=" + text + "><size=11>" + school + "</size></color>  <size=10><color=#555>" + val.voiceCommandKey + "</color></size>", _header, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				GUILayout.Label("<size=10><color=#4a4> BASE </color></size>", _subLabel, Array.Empty<GUILayoutOption>());
				GUILayout.EndHorizontal();
			}
			else
			{
				SpellVariantDef spellVariantDef = _variants[_selVariant];
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("<b><size=15>" + spellVariantDef.VoiceCommand + "</size></b>  <size=10><color=#555>" + spellVariantDef.LocKey + "</color></size>", _header, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				GUILayout.Label("<size=10><color=#4080ff> VARIANT </color></size>", _subLabel, Array.Empty<GUILayoutOption>());
				Color backgroundColor = GUI.backgroundColor;
				GUI.backgroundColor = new Color(0.55f, 0.18f, 0.18f);
				if (GUILayout.Button("Delete", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
				{
					SpellInterpreter.DeleteVariant(spellVariantDef.LocKey);
					_variants = SpellInterpreter.GetAllVariants().ToList();
					SelectVariant(-1);
					GUI.backgroundColor = backgroundColor;
					return;
				}
				GUI.backgroundColor = backgroundColor;
				GUILayout.EndHorizontal();
			}
			DrawSeparator();
			GUILayout.Space(4f);
			DrawPipelineBar();
			GUILayout.Space(4f);
			DrawSeparator();
			GUILayout.Space(4f);
			_nodeScroll = GUILayout.BeginScrollView(_nodeScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			DrawNodePanel();
			GUILayout.EndScrollView();
			if (flag2)
			{
				DrawSeparator();
				GUILayout.Space(4f);
				DrawVariantFooter();
			}
		}

		private void DrawPipelineBar()
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			for (int i = 0; i < NodeNames.Length; i++)
			{
				string nodeSummary = GetNodeSummary(i);
				if (GUILayout.Button("<b>" + NodeNames[i] + "</b>\n<size=9><color=#aaa>" + nodeSummary + "</color></size>", (i == _selectedNode) ? _nodeBtnSel : _nodeBtn, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(140f),
					GUILayout.Height(44f)
				}))
				{
					_selectedNode = i;
				}
				if (i < NodeNames.Length - 1)
				{
					GUILayout.Label("<color=#333> › </color>", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(16f) });
				}
			}
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
		}

		private string GetNodeSummary(int node)
		{
			if (_selectedIsVariant && _selVariant >= 0 && _selVariant < _variants.Count)
			{
				SpellVariantDef spellVariantDef = _variants[_selVariant];
				switch (node)
				{
				case 0:
					return string.IsNullOrEmpty(spellVariantDef.VoiceCommand) ? "—" : spellVariantDef.VoiceCommand;
				case 1:
				{
					GateDef? gate = spellVariantDef.Gate;
					return (gate != null && gate.Mode == GateMode.Delegate) ? ("→ " + (spellVariantDef.Gate.DelegateTo ?? "?")) : (spellVariantDef.Gate?.Mode.ToString() ?? "OwnCharges");
				}
				case 2:
				{
					ActivationDef? activation = spellVariantDef.Activation;
					return (activation != null && activation.SuppressCasterVfx) ? "VFX off" : "default";
				}
				case 3:
					return spellVariantDef.Targeting?.Method.ToString() ?? "None";
				case 4:
					return (spellVariantDef.Effects.Count == 0) ? "none" : $"{spellVariantDef.Effects.Count} effect(s)";
				default:
					return "—";
				}
			}
			if (!_selectedIsVariant && _selectedIndex >= 0 && _selectedIndex < _filtered.Count)
			{
				return node switch
				{
					0 => (_editTrigger.Length > 0) ? _editTrigger : _editKey, 
					1 => (_chargeFields.Count > 0) ? "editable" : "—", 
					2 => "read-only", 
					3 => "read-only", 
					4 => "read-only", 
					_ => "—", 
				};
			}
			return "—";
		}

		private void DrawNodePanel()
		{
			if (_selectedIsVariant && _selVariant >= 0 && _selVariant < _variants.Count)
			{
				SpellVariantDef v = _variants[_selVariant];
				switch (_selectedNode)
				{
				case 0:
					DrawVariantVoiceNode(v);
					break;
				case 1:
					DrawVariantChargesNode(v);
					break;
				case 2:
					DrawVariantActivationNode(v);
					break;
				case 3:
					DrawVariantTargetingNode(v);
					break;
				case 4:
					DrawVariantEffectsNode(v);
					break;
				}
			}
			else if (!_selectedIsVariant && _selectedIndex >= 0 && _selectedIndex < _filtered.Count)
			{
				SpellData sd = _filtered[_selectedIndex];
				switch (_selectedNode)
				{
				case 0:
					DrawBaseVoiceNode(sd);
					break;
				case 1:
					DrawBaseChargesNode(sd);
					break;
				case 2:
					DrawBaseActivationNode(sd);
					break;
				case 3:
					DrawBaseTargetingNode(sd);
					break;
				case 4:
					DrawBaseEffectsNode(sd);
					break;
				}
			}
		}

		private void DrawBaseVoiceNode(SpellData sd)
		{
			PipelineSection("Voice");
			GUILayout.Space(6f);
			GUILayout.Label("Voice Key  <size=10><color=#555>internal command identifier</color></size>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			_editKey = GUILayout.TextField(_editKey, Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Assign", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				AssignKey(sd, _editKey);
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(12f);
			GUILayout.Label("Trigger  <size=10><color=#555>what you say — hyphens or spaces</color></size>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			_editTrigger = GUILayout.TextField(_editTrigger, Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Apply", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				ApplyTrigger(_editKey, _editTrigger);
			}
			GUILayout.EndHorizontal();
		}

		private void DrawBaseChargesNode(SpellData sd)
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: 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_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			PipelineSection("Charges");
			GUILayout.Space(6f);
			if (_chargeFields.Count == 0)
			{
				GUILayout.Label("  <color=#555>No charge fields found on this SpellData.</color>", _subLabel, Array.Empty<GUILayoutOption>());
				return;
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("<color=#555>Field</color>", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
			GUILayout.Label("<color=#555>Current</color>", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
			GUILayout.Label("<color=#555>New value</color>", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUILayout.EndHorizontal();
			DrawSeparator();
			GUILayout.Space(2f);
			for (int i = 0; i < _chargeFields.Count; i++)
			{
				(FieldInfo field, string draft, string live) tuple = _chargeFields[i];
				FieldInfo item = tuple.field;
				string item2 = tuple.draft;
				string item3 = tuple.live;
				bool flag = item2 != item3;
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label(item.Name, _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
				Color color = GUI.color;
				GUI.color = new Color(1f, 1f, 1f, 0.35f);
				GUILayout.Label(item3, _fieldVal, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
				GUI.color = color;
				Color backgroundColor = GUI.backgroundColor;
				if (flag)
				{
					GUI.backgroundColor = new Color(0.25f, 0.45f, 0.25f);
				}
				string text = GUILayout.TextField(item2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				GUI.backgroundColor = backgroundColor;
				if (text != item2)
				{
					_chargeFields[i] = (item, text, item3);
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.Space(10f);
			bool num = _chargeFields.Any<(FieldInfo, string, string)>(((FieldInfo field, string draft, string live) f) => f.draft != f.live);
			Color backgroundColor2 = GUI.backgroundColor;
			GUI.backgroundColor = (num ? new Color(0.25f, 0.6f, 0.25f) : new Color(0.3f, 0.3f, 0.3f));
			GUI.enabled = num;
			if (GUILayout.Button("Apply Changes", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				ApplyChargeFields(sd);
				LoadChargeFields(sd);
			}
			GUI.enabled = true;
			GUI.backgroundColor = backgroundColor2;
		}

		private void DrawBaseActivationNode(SpellData sd)
		{
			PipelineSection("Activation");
			GUILayout.Space(6f);
			GUILayout.Label("  <color=#555>Activation behavior is defined by the base spell component.</color>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			ReadOnlyRow("Component type", GetSpellComponentType(sd));
			ReadOnlyRow("Cast animation", GetCastAnimationType(sd));
			GUILayout.Space(12f);
			GUILayout.Label("  <color=#555>Create a variant to suppress caster VFX on activation.</color>", _subLabel, Array.Empty<GUILayoutOption>());
		}

		private void DrawBaseTargetingNode(SpellData sd)
		{
			PipelineSection("Targeting");
			GUILayout.Space(6f);
			GUILayout.Label("  <color=#555>Targeting is baked into the base spell component.</color>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			ReadOnlyRow("Component type", GetSpellComponentType(sd));
			GUILayout.Space(12f);
			GUILayout.Label("  <color=#555>Create a variant to override with SphereCast or Raycast targeting.</color>", _subLabel, Array.Empty<GUILayoutOption>());
		}

		private void DrawBaseEffectsNode(SpellData sd)
		{
			PipelineSection("Effects");
			GUILayout.Space(6f);
			GUILayout.Label("  <color=#555>Effects are handled by the base spell component.</color>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			ReadOnlyRow("Component type", GetSpellComponentType(sd));
			GUILayout.Space(12f);
			GUILayout.Label("  <color=#555>Create a variant to add data-driven effects (e.g. TriggerSpell).</color>", _subLabel, Array.Empty<GUILayoutOption>());
		}

		private void DrawVariantVoiceNode(SpellVariantDef v)
		{
			PipelineSection("Voice / Identity");
			GUILayout.Space(6f);
			v.VoiceCommand = PipelineRow("Voice command", v.VoiceCommand);
			GUILayout.Label("  <color=#555>The phrase you speak to cast. e.g. UP-BLAST</color>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			v.BaseSpellKey = PipelineRow("Base spell key", v.BaseSpellKey);
			GUILayout.Label("  <color=#555>Voice key of the Unity component to clone. e.g. SPELL_BAS_UPDRAFT</color>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			ReadOnlyRow("LocKey", v.LocKey);
		}

		private void DrawVariantChargesNode(SpellVariantDef v)
		{
			PipelineSection("Gate  <size=10><color=#555>when the spell can fire</color></size>");
			GUILayout.Space(4f);
			if (v.Gate == null)
			{
				GateDef gateDef = (v.Gate = new GateDef());
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("  Mode:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			v.Gate.Mode = EnumToggle(v.Gate.Mode);
			GUILayout.EndHorizontal();
			if (v.Gate.Mode == GateMode.Delegate)
			{
				GUILayout.Space(4f);
				v.Gate.DelegateTo = PipelineRow("Delegate to", v.Gate.DelegateTo ?? "");
				_draftMinCharges = PipelineRow("Min charges", _draftMinCharges);
			}
			GUILayout.Space(12f);
			PipelineSection("Charge  <size=10><color=#555>which pool to consume</color></size>");
			GUILayout.Space(4f);
			bool flag = v.Charge != null;
			bool flag2 = EnableToggle("Configure charge override", flag);
			if (flag2 != flag)
			{
				v.Charge = (flag2 ? new ChargeDef() : null);
			}
			if (v.Charge != null)
			{
				GUILayout.Space(4f);
				v.Charge.Source = PipelineRow("Source spell", v.Charge.Source);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("  Consume on:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
				v.Charge.ConsumeOn = EnumToggle(v.Charge.ConsumeOn);
				GUILayout.EndHorizontal();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("  On miss:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
				v.Charge.OnMiss = EnumToggle(v.Charge.OnMiss);
				GUILayout.EndHorizontal();
			}
		}

		private void DrawVariantActivationNode(SpellVariantDef v)
		{
			PipelineSection("Activation  <size=10><color=#555>on cast</color></size>");
			GUILayout.Space(6f);
			bool flag = v.Activation != null;
			bool flag2 = EnableToggle("Configure activation override", flag);
			if (flag2 != flag)
			{
				v.Activation = (flag2 ? new ActivationDef() : null);
			}
			if (v.Activation != null)
			{
				GUILayout.Space(4f);
				bool flag3 = EnableToggle("Suppress caster VFX", v.Activation.SuppressCasterVfx);
				if (flag3 != v.Activation.SuppressCasterVfx)
				{
					v.Activation.SuppressCasterVfx = flag3;
				}
			}
		}

		private void DrawVariantTargetingNode(SpellVariantDef v)
		{
			PipelineSection("Targeting  <size=10><color=#555>who gets hit</color></size>");
			GUILayout.Space(6f);
			if (v.Targeting == null)
			{
				TargetingDef targetingDef = (v.Targeting = new TargetingDef());
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("  Method:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			v.Targeting.Method = EnumToggle(v.Targeting.Method);
			GUILayout.EndHorizontal();
			if (v.Targeting.Method != TargetingMethod.None)
			{
				GUILayout.Space(4f);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("  Radius:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
				_draftRadius = GUILayout.TextField(_draftRadius, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) });
				GUILayout.Space(14f);
				GUILayout.Label("Max dist:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(66f) });
				_draftMaxDist = GUILayout.TextField(_draftMaxDist, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) });
				GUILayout.EndHorizontal();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("  Filter:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
				v.Targeting.Filter = EnumToggle(v.Targeting.Filter);
				GUILayout.EndHorizontal();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				v.Targeting.ClipToWalls = BoolToggle("  Clip walls", v.Targeting.ClipToWalls);
				GUILayout.Space(10f);
				v.Targeting.ExcludeSelf = BoolToggle("  Excl. self", v.Targeting.ExcludeSelf);
				GUILayout.Space(10f);
				v.Targeting.ExcludeDecoys = BoolToggle("  Excl. decoys", v.Targeting.ExcludeDecoys);
				GUILayout.EndHorizontal();
			}
		}

		private void DrawVariantEffectsNode(SpellVariantDef v)
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			PipelineSection("Effects  <size=10><color=#555>what happens on hit</color></size>");
			GUILayout.Space(6f);
			for (int num = v.Effects.Count - 1; num >= 0; num--)
			{
				EffectDef effectDef = v.Effects[num];
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("  <b>" + effectDef.Type + "</b>", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
				if (effectDef.Type == "TriggerSpell")
				{
					GUILayout.Label("spell:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(38f) });
					effectDef.SpellKey = GUILayout.TextField(effectDef.SpellKey ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) });
				}
				GUILayout.FlexibleSpace();
				effectDef.Route = EnumToggle(effectDef.Route);
				Color backgroundColor = GUI.backgroundColor;
				GUI.backgroundColor = new Color(0.55f, 0.18f, 0.18f);
				if (GUILayout.Button("✕", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(24f) }))
				{
					v.Effects.RemoveAt(num);
				}
				GUI.backgroundColor = backgroundColor;
				GUILayout.EndHorizontal();
			}
			GUILayout.Space(6f);
			if (_addingEffect)
			{
				DrawAddEffectPanel(v);
			}
			else if (GUILayout.Button("+ Add Effect", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
			{
				_addingEffect = true;
				_addEffectTypeIdx = 0;
				_addEffectSpellKey = "";
			}
		}

		private void DrawVariantFooter()
		{
			//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_009e: Unknown result type (might be due to invalid IL or missing references)
			string[] variantErrors = _variantErrors;
			foreach (string text in variantErrors)
			{
				GUILayout.Label("  <color=#e06060>⚠  " + text + "</color>", _subLabel, Array.Empty<GUILayoutOption>());
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			Color backgroundColor = GUI.backgroundColor;
			GUI.backgroundColor = new Color(0.22f, 0.52f, 0.22f);
			if (GUILayout.Button("Apply", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
			{
				ApplyVariant(_variants[_selVariant]);
			}
			GUI.backgroundColor = backgroundColor;
			GUILayout.Space(6f);
			if (GUILayout.Button("Save JSON", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
			{
				SpellInterpreter.SaveVariants();
			}
			GUILayout.Space(6f);
			if (GUILayout.Button("Reload JSON", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
			{
				SpellInterpreter.ReloadVariants();
				_variants = SpellInterpreter.GetAllVariants().ToList();
				SelectVariant(-1);
			}
			GUILayout.EndHorizontal();
		}

		private void StartWizard()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			_wizardActive = true;
			_wizardStep = 0;
			_wizardError = "";
			_addingEffect = false;
			_draftMinCharges = "1";
			_wizardRadius = "0.50";
			_wizardMaxDist = "20.0";
			_newLocKey = "SPELL_CUSTOM_";
			_newBaseKey = "";
			_newVoiceCmd = "";
			_wizardDef = new SpellVariantDef
			{
				Gate = new GateDef
				{
					Mode = GateMode.OwnCharges
				},
				Targeting = new TargetingDef
				{
					Method = TargetingMethod.None
				}
			};
			_variantDetailScroll = Vector2.zero;
		}

		private void CancelWizard()
		{
			_wizardActive = false;
			_wizardStep = 0;
			_wizardError = "";
			_addingEffect = false;
		}

		private void AdvanceWizard()
		{
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			_wizardError = "";
			switch (_wizardStep)
			{
			case 0:
			{
				string key = _newLocKey.Trim().ToUpperInvariant();
				if (string.IsNullOrEmpty(key))
				{
					_wizardError = "Internal key is required.";
					return;
				}
				if (string.IsNullOrWhiteSpace(_newBaseKey))
				{
					_wizardError = "Base spell key is required.";
					return;
				}
				if (string.IsNullOrWhiteSpace(_newVoiceCmd))
				{
					_wizardError = "Voice command is required.";
					return;
				}
				if (SpellInterpreter.GetAllVariants().Any((SpellVariantDef v) => v.LocKey == key))
				{
					_wizardError = "'" + key + "' already exists.";
					return;
				}
				_wizardDef.LocKey = key;
				_wizardDef.BaseSpellKey = _newBaseKey.Trim();
				_wizardDef.VoiceCommand = _newVoiceCmd.Trim().ToUpperInvariant();
				break;
			}
			case 1:
			{
				GateDef? gate = _wizardDef.Gate;
				if (gate != null && gate.Mode == GateMode.Delegate && string.IsNullOrWhiteSpace(_wizardDef.Gate.DelegateTo))
				{
					_wizardError = "Delegate mode requires a parent spell key.";
					return;
				}
				if (_wizardDef.Gate != null && int.TryParse(_draftMinCharges, out var result3))
				{
					_wizardDef.Gate.MinCharges = result3;
				}
				break;
			}
			case 2:
				if (_wizardDef.Targeting != null)
				{
					if (float.TryParse(_wizardRadius, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						_wizardDef.Targeting.Radius = result;
					}
					if (float.TryParse(_wizardMaxDist, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
					{
						_wizardDef.Targeting.MaxDistance = result2;
					}
				}
				break;
			}
			_wizardStep++;
			_variantDetailScroll = Vector2.zero;
		}

		private void FinishWizard()
		{
			_wizardError = "";
			if (!SpellInterpreter.UpdateVariant(_wizardDef, out var result))
			{
				_wizardError = ((result.Errors.Count > 0) ? result.Errors[0] : "Validation failed.");
				return;
			}
			_variants = SpellInterpreter.GetAllVariants().ToList();
			int i = _variants.FindIndex((SpellVariantDef v) => v.LocKey == _wizardDef.LocKey);
			CancelWizard();
			SelectVariant(i);
		}

		private void DrawWizard()
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: 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_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			for (int i = 0; i < WizardStepNames.Length; i++)
			{
				GUILayout.Label((i < _wizardStep) ? ("<color=#4a4>✓ " + WizardStepNames[i] + "</color>") : ((i == _wizardStep) ? ("<b>" + WizardStepNames[i] + "</b>") : ("<color=#444>" + WizardStepNames[i] + "</color>")), _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(76f) });
				if (i < WizardStepNames.Length - 1)
				{
					GUILayout.Label("<color=#333>›</color>", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(12f) });
				}
			}
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			DrawSeparator();
			GUILayout.Space(6f);
			_variantDetailScroll = GUILayout.BeginScrollView(_variantDetailScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			switch (_wizardStep)
			{
			case 0:
				DrawWizardIdentity();
				break;
			case 1:
				DrawWizardGate();
				break;
			case 2:
				DrawWizardTargeting();
				break;
			case 3:
				DrawWizardEffects();
				break;
			case 4:
				DrawWizardReview();
				break;
			}
			GUILayout.EndScrollView();
			GUILayout.Space(6f);
			DrawSeparator();
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (_wizardStep > 0 && GUILayout.Button("◀ Back", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
			{
				_wizardStep--;
				_wizardError = "";
				_variantDetailScroll = Vector2.zero;
			}
			GUILayout.FlexibleSpace();
			if (!string.IsNullOrEmpty(_wizardError))
			{
				GUILayout.Label("<color=#e06060>" + _wizardError + "</color>", _subLabel, Array.Empty<GUILayoutOption>());
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Cancel", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				CancelWizard();
			}
			GUILayout.Space(6f);
			if (_wizardStep < 4)
			{
				if (GUILayout.Button("Next ▶", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
				{
					AdvanceWizard();
				}
			}
			else
			{
				Color backgroundColor = GUI.backgroundColor;
				GUI.backgroundColor = new Color(0.22f, 0.52f, 0.22f);
				if (GUILayout.Button("Create Spell", _tab, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
				{
					FinishWizard();
				}
				GUI.backgroundColor = backgroundColor;
			}
			GUILayout.EndHorizontal();
		}

		private void DrawWizardIdentity()
		{
			GUILayout.Label("<b>Step 1 — Identity</b>", _header, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			GUILayout.Label("A variant reuses an existing spell's Unity component but defines its own\nvoice command, gating, targeting, and effects through data — no code required.", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(14f);
			_newLocKey = PipelineRow("Internal key", _newLocKey);
			GUILayout.Label("  <color=#555>Unique identifier. Convention: SPELL_<SCHOOL>_<NAME>  e.g. SPELL_ARC_VOID_BOLT</color>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			_newBaseKey = PipelineRow("Base spell key", _newBaseKey);
			GUILayout.Label("  <color=#555>Voice key of the spell whose Unity component to clone  e.g. SPELL_BAS_UPDRAFT</color>", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			_newVoiceCmd = PipelineRow("Voice command", _newVoiceCmd);
			GUILayout.Label("  <color=#555>The phrase you speak to cast. Hyphens separate syllables  e.g. UP-BLAST</color>", _subLabel, Array.Empty<GUILayoutOption>());
		}

		private void DrawWizardGate()
		{
			GUILayout.Label("<b>Step 2 — Gate</b>", _header, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			GUILayout.Label("The gate controls whether the spell is allowed to activate when you speak the command.", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(14f);
			SpellVariantDef wizardDef = _wizardDef;
			if (wizardDef.Gate == null)
			{
				GateDef gateDef = (wizardDef.Gate = new GateDef());
			}
			DrawWizardOption(_wizardDef.Gate.Mode == GateMode.OwnCharges, "Own charges", "Uses its own independent charge pool. Good for spells with their own cooldown.", delegate
			{
				_wizardDef.Gate.Mode = GateMode.OwnCharges;
			});
			DrawWizardOption(_wizardDef.Gate.Mode == GateMode.Delegate, "Delegate", "Borrows another spell's charges. Only fires when the parent has enough charges.", delegate
			{
				_wizardDef.Gate.Mode = GateMode.Delegate;
			});
			DrawWizardOption(_wizardDef.Gate.Mode == GateMode.Always, "Always", "No charge check — always fires when spoken. No cooldown protection.", delegate
			{
				_wizardDef.Gate.Mode = GateMode.Always;
			});
			if (_wizardDef.Gate.Mode == GateMode.Delegate)
			{
				GUILayout.Space(10f);
				_wizardDef.Gate.DelegateTo = PipelineRow("Parent spell key", _wizardDef.Gate.DelegateTo ?? "");
				GUILayout.Label("  <color=#555>Voice key of the spell whose charges to borrow  e.g. SPELL_BAS_UPDRAFT</color>", _subLabel, Array.Empty<GUILayoutOption>());
				GUILayout.Space(4f);
				_draftMinCharges = PipelineRow("Min charges required", _draftMinCharges);
			}
		}

		private void DrawWizardTargeting()
		{
			GUILayout.Label("<b>Step 3 — Targeting</b>", _header, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			GUILayout.Label("Choose how the spell locates a pawn to apply effects to when you cast it.", _subLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(14f);
			SpellVariantDef wizardDef = _wizardDef;
			if (wizardDef.Targeting == null)
			{
				TargetingDef targetingDef = (wizardDef.Targeting = new TargetingDef());
			}
			DrawWizardOption(_wizardDef.Targeting.Method == TargetingMethod.None, "None", "No targeting. Activates without seeking a hit target.", delegate
			{
				_wizardDef.Targeting.Method = TargetingMethod.None;
			});
			DrawWizardOption(_wizardDef.Targeting.Method == TargetingMethod.SphereCast, "Sphere cast", "A sphere sweeps forward from your gaze — hits the first valid pawn in the swept volume.", delegate
			{
				_wizardDef.Targeting.Method = TargetingMethod.SphereCast;
			});
			DrawWizardOption(_wizardDef.Targeting.Method == TargetingMethod.Raycast, "Raycast", "A precise ray — only hits exactly what you're looking directly at.", delegate
			{
				_wizardDef.Targeting.Method = TargetingMethod.Raycast;
			});
			if (_wizardDef.Targeting.Method != TargetingMethod.None)
			{
				GUILayout.Space(10f);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("  Radius:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
				_wizardRadius = GUILayout.TextField(_wizardRadius, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) });
				GUILayout.Space(14f);
				GUILayout.Label("Max dist:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(66f) });
				_wizardMaxDist = GUILayout.TextField(_wizardMaxDist, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) });
				GUILayout.EndHorizontal();
				GUILayout.Space(4f);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("  Filter:", _subLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
				_wizardDef.Targeting.Filter = EnumToggle(_wizardDef.Targeting.Filter);
				GUILayout.EndHorizontal();
				GUILayout.Space(4f);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				_wizardDef.Targeting.ClipToWalls = BoolToggle("  Clip to walls", _wizardDef.Targeting.ClipToWalls);
				GUILayout.Space(10f);
				_wizardDef.Targeting.ExcludeSelf = BoolToggle("  Exclude self", _wizardDef.Targetin