Decompiled source of SkyforgeFireworks v0.6.0

BepInEx/plugins/SkyforgeFireworks/SkyforgeFireworks.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Audio;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("SkyforgeFireworks.PrivateTests")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SkyforgeFireworks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.6.0.0")]
[assembly: AssemblyInformationalVersion("0.6.0")]
[assembly: AssemblyProduct("SkyforgeFireworks")]
[assembly: AssemblyTitle("SkyforgeFireworks")]
[assembly: AssemblyVersion("0.6.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SkyforgeFireworks
{
	internal static class CarvingCodec
	{
		internal static string Encode(ShowSettings plan)
		{
			if (plan == null || !plan.Valid)
			{
				throw new ArgumentException("Invalid launcher carving");
			}
			return string.Join("|", "2", plan.Rune.ToString(CultureInfo.InvariantCulture), plan.Shots.ToString(CultureInfo.InvariantCulture), plan.Pattern.ToString(CultureInfo.InvariantCulture), plan.Delay.ToString("R", CultureInfo.InvariantCulture), plan.Interval.ToString("R", CultureInfo.InvariantCulture), plan.Fuse.ToString("R", CultureInfo.InvariantCulture), plan.Spread.ToString(CultureInfo.InvariantCulture), plan.Preset.ToString(CultureInfo.InvariantCulture));
		}

		internal static bool TryDecode(string text, out ShowSettings plan)
		{
			plan = null;
			if (string.IsNullOrEmpty(text) || text.Length > 256)
			{
				return false;
			}
			string[] array = text.Split(new char[1] { '|' });
			bool flag = array.Length == 7 && array[0] == "1";
			if (!flag && (array.Length != 9 || !(array[0] == "2")))
			{
				return false;
			}
			ShowSettings showSettings = new ShowSettings();
			CultureInfo invariantCulture = CultureInfo.InvariantCulture;
			if (!int.TryParse(array[1], NumberStyles.Integer, invariantCulture, out showSettings.Rune) || !int.TryParse(array[2], NumberStyles.Integer, invariantCulture, out showSettings.Shots) || !int.TryParse(array[3], NumberStyles.Integer, invariantCulture, out showSettings.Pattern) || !float.TryParse(array[4], NumberStyles.Float, invariantCulture, out showSettings.Delay) || !float.TryParse(array[5], NumberStyles.Float, invariantCulture, out showSettings.Interval) || !float.TryParse(array[6], NumberStyles.Float, invariantCulture, out showSettings.Fuse) || (!flag && (!int.TryParse(array[7], NumberStyles.Integer, invariantCulture, out showSettings.Spread) || !int.TryParse(array[8], NumberStyles.Integer, invariantCulture, out showSettings.Preset))) || !showSettings.Valid)
			{
				return false;
			}
			plan = showSettings;
			return true;
		}
	}
	public sealed class FireworkPiece : MonoBehaviour, Hoverable, Interactable
	{
		internal sealed class PreviewRow
		{
			internal string Name;

			internal string Status;

			internal float Distance;

			internal float Delay;

			internal float Interval;

			internal int Planned;

			internal int Available;

			internal bool Included;

			internal int Shots => Math.Min(Planned, Available);
		}

		public int Kind;

		internal static readonly HashSet<FireworkPiece> All = new HashSet<FireworkPiece>();

		private const string RequestRpc = "Skyforge_Request_3";

		private const string ArmRpc = "Skyforge_Arm_2";

		private const string NoticeRpc = "Skyforge_Notice_1";

		internal ZNetView View;

		private Container box;

		private bool wasOwner;

		private float nextTick;

		private List<FireworkPiece> targets;

		private double showDuration;

		private ZDOID actorId;

		private long actorPeer;

		private FuseVisual fuse;

		internal int LastNotice { get; private set; }

		internal static long Now
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return 0L;
				}
				return ZNet.instance.GetTime().Ticks;
			}
		}

		internal bool Ready
		{
			get
			{
				if (Object.op_Implicit((Object)(object)View))
				{
					return View.IsValid();
				}
				return false;
			}
		}

		internal ZDO Data => View.GetZDO();

		internal long StartTime
		{
			get
			{
				if (!Ready)
				{
					return 0L;
				}
				return Data.GetLong("SF_start", 0L);
			}
		}

		internal bool Running => StartTime > 0;

		internal ShowSettings Settings => new ShowSettings
		{
			Pattern = Data.GetInt("SF_pattern", 0),
			Spread = Data.GetInt("SF_spread", 0),
			Preset = Data.GetInt("SF_preset", 0),
			Rune = Data.GetInt("SF_rune", 1),
			Delay = Data.GetFloat("SF_delay", 0f),
			Interval = Data.GetFloat("SF_interval", 1f),
			Shots = Data.GetInt("SF_shots", (Kind == 0) ? 1 : 6),
			Fuse = Data.GetFloat("SF_fuse", 6f)
		};

		internal ShowSettings RunSettings
		{
			get
			{
				ShowSettings settings = Settings;
				if (Data.GetBool("SF_runPlan", false))
				{
					settings.Pattern = Data.GetInt("SF_runPattern", settings.Pattern);
					settings.Spread = Data.GetInt("SF_runSpread", settings.Spread);
					settings.Shots = Data.GetInt("SF_runShots", settings.Shots);
					settings.Delay = Data.GetFloat("SF_runDelay", settings.Delay);
					settings.Interval = Data.GetFloat("SF_runInterval", settings.Interval);
				}
				return settings;
			}
		}

		internal string Label
		{
			get
			{
				if (Kind != 2)
				{
					if (Kind != 1)
					{
						return "Launch stand";
					}
					return "Salvo rack";
				}
				return "Show fuse board";
			}
		}

		private void SetRunSettings(ShowSettings plan)
		{
			Data.Set("SF_runPattern", plan.Pattern);
			Data.Set("SF_runSpread", (Kind == 1) ? plan.Spread : 0);
			Data.Set("SF_runShots", plan.Shots);
			Data.Set("SF_runDelay", plan.Delay);
			Data.Set("SF_runInterval", plan.Interval);
			Data.Set("SF_runPlan", true);
		}

		internal ShowSettings PlannedFor(FireworkPiece launcher, int index, int count, int preset)
		{
			if (preset != 0)
			{
				return ShowPresets.Plan(preset, index, count, launcher.Settings);
			}
			return launcher.Settings;
		}

		private void Start()
		{
			View = ((Component)this).GetComponent<ZNetView>();
			box = ((Component)this).GetComponent<Container>();
			if (!Ready)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			View.Register<ZPackage>("Skyforge_Request_3", (Action<long, ZPackage>)OnRequest);
			View.Register<ZPackage>("Skyforge_Arm_2", (Action<long, ZPackage>)OnArm);
			View.Register<int>("Skyforge_Notice_1", (Action<long, int>)OnNotice);
			wasOwner = View.IsOwner();
			if (wasOwner)
			{
				Stop();
			}
			All.Add(this);
			fuse = ((Component)this).gameObject.AddComponent<FuseVisual>();
		}

		private void OnDestroy()
		{
			All.Remove(this);
			if ((Object)(object)SettingsPanel.Target == (Object)(object)this)
			{
				SettingsPanel.Close();
			}
		}

		internal static bool HasTorch(Player actor)
		{
			object obj;
			if (!Object.op_Implicit((Object)(object)actor))
			{
				obj = null;
			}
			else
			{
				ZNetView component = ((Component)actor).GetComponent<ZNetView>();
				obj = ((component != null) ? component.GetZDO() : null);
			}
			ZDO val = (ZDO)obj;
			int stableHashCode = StringExtensionMethods.GetStableHashCode("Torch");
			if (val != null && (val.GetInt(ZDOVars.s_leftItem, 0) == stableHashCode || val.GetInt(ZDOVars.s_rightItem, 0) == stableHashCode))
			{
				return !((Character)actor).IsDead();
			}
			return false;
		}

		public string GetHoverName()
		{
			return Label;
		}

		public float GetHoverOffset()
		{
			return 0.8f;
		}

		public string GetHoverText()
		{
			if (!Ready)
			{
				return Label;
			}
			string text = Label + " · Rune " + Settings.Rune;
			if (Running)
			{
				double num = (double)(StartTime - Now) / 10000000.0;
				text += ((num > 0.0) ? ("\nFuse burning · " + Math.Ceiling(num) + "s") : "\nShow in progress");
				return Localization.instance.Localize(text + "\n[<color=yellow>$KEY_Use</color>] Snuff / stop remaining shots");
			}
			if (Kind < 2)
			{
				text = text + "\n" + VikingRocket.PatternName(Settings.Pattern) + " - loaded for " + AvailableShots() + " shots";
				text = text + "\n" + Settings.Shots + " planned - delay " + Settings.Delay + "s - every " + Settings.Interval + "s";
				text += (HasTorch(Player.m_localPlayer) ? "\nPut away your torch to open the ammunition box." : "\n[<color=yellow>$KEY_Use</color>] Load fireworks");
			}
			else
			{
				text += "\nLinks matching runes within 40m (up to 16 launchers)";
			}
			text += "\n[<color=yellow>Shift + $KEY_Use</color>] Arrange show\nEquip torch + [<color=yellow>$KEY_Use</color>] Light fuse";
			return Localization.instance.Localize(text);
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (hold || !Ready || (Object)(object)user != (Object)(object)Player.m_localPlayer || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false))
			{
				return false;
			}
			if (Running)
			{
				Request(2);
				return true;
			}
			if (alt || !HasTorch((Player)(object)((user is Player) ? user : null)))
			{
				SettingsPanel.Open(this);
				return true;
			}
			Request(1);
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			object obj;
			if (item == null)
			{
				obj = null;
			}
			else
			{
				GameObject dropPrefab = item.m_dropPrefab;
				obj = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
			}
			if ((string?)obj != "Torch" || (Object)(object)user != (Object)(object)Player.m_localPlayer || !Ready)
			{
				return false;
			}
			if (!HasTorch((Player)(object)((user is Player) ? user : null)))
			{
				((Character)user).Message((MessageType)2, "Equip your torch, then use it on the fuse.", 0, (Sprite)null, false);
				return true;
			}
			if (!Running && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false))
			{
				Request(1);
			}
			return true;
		}

		internal unsafe void Request(int action, ShowSettings settings = null)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (Ready && Object.op_Implicit((Object)(object)localPlayer))
			{
				ZPackage val = new ZPackage();
				val.Write(((Character)localPlayer).GetZDOID());
				val.Write(Now);
				val.Write(action);
				if (action == 0)
				{
					val.Write(settings.Rune);
					val.Write(settings.Delay);
					val.Write(settings.Interval);
					val.Write(settings.Shots);
					val.Write(settings.Fuse);
					val.Write(settings.Pattern);
					val.Write(settings.Spread);
					val.Write(settings.Preset);
				}
				string[] obj = new string[10]
				{
					"Request action=",
					action.ToString(),
					" target=",
					null,
					null,
					null,
					null,
					null,
					null,
					null
				};
				ZDOID uid = Data.m_uid;
				obj[3] = ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
				obj[4] = " owner=";
				obj[5] = Data.GetOwner().ToString();
				obj[6] = " local=";
				obj[7] = ZNet.GetUID().ToString();
				obj[8] = " registered=";
				obj[9] = ((Object)(object)ZNetScene.instance.FindInstance(Data.m_uid) == (Object)(object)((Component)this).gameObject).ToString();
				Plugin.Note(string.Concat(obj));
				View.InvokeRPC("Skyforge_Request_3", new object[1] { val });
			}
		}

		private static Player Actor(ZDOID id, long sender)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			ZNetScene instance = ZNetScene.instance;
			GameObject val = ((instance != null) ? instance.FindInstance(id) : null);
			ZNetView val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ZNetView>() : null);
			if (!Object.op_Implicit((Object)(object)val2) || !val2.IsValid() || val2.GetZDO().GetOwner() != sender)
			{
				return null;
			}
			return val.GetComponent<Player>();
		}

		private static bool Access(Player player, Vector3 pos)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player) || player.GetPlayerID() == 0L)
			{
				return false;
			}
			bool flag = false;
			foreach (PrivateArea item in (List<PrivateArea>)AccessTools.Field(typeof(PrivateArea), "m_allAreas").GetValue(null))
			{
				if (Object.op_Implicit((Object)(object)item) && (bool)AccessTools.Method(typeof(PrivateArea), "IsEnabled", (Type[])null, (Type[])null).Invoke(item, null) && (bool)AccessTools.Method(typeof(PrivateArea), "IsInside", (Type[])null, (Type[])null).Invoke(item, new object[2] { pos, 0f }))
				{
					if (((Component)item).GetComponent<Piece>().GetCreator() == player.GetPlayerID() || (bool)AccessTools.Method(typeof(PrivateArea), "IsPermitted", (Type[])null, (Type[])null).Invoke(item, new object[1] { player.GetPlayerID() }))
					{
						return true;
					}
					flag = true;
				}
			}
			return !flag;
		}

		private void Notice(long peer, int code)
		{
			View.InvokeRPC(peer, "Skyforge_Notice_1", new object[1] { code });
		}

		private void OnNotice(long sender, int code)
		{
			if (Ready && sender == Data.GetOwner() && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				string text = code switch
				{
					5 => "This saved arrangement is invalid. Open Arrange and carve valid settings.", 
					4 => "Load fireworks into this launcher first.", 
					3 => "Close the ammunition box before lighting its fuse.", 
					2 => "Another show is already using this rune nearby.", 
					1 => "Load fireworks into a nearby launcher on this rune first.", 
					_ => null, 
				};
				if (text != null)
				{
					LastNotice = code;
					((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
				}
			}
		}

		internal int AvailableShots()
		{
			if (!Ready || !Object.op_Implicit((Object)(object)box))
			{
				return 0;
			}
			if (!box.IsInUse())
			{
				AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null).Invoke(box, null);
			}
			FireworkItem value;
			return (from i in box.GetInventory().GetAllItems()
				group i by i.m_shared.m_name).Sum((IGrouping<string, ItemData> group) => Plugin.Ammunition.TryGetValue(group.Key, out value) ? (group.Sum((ItemData i) => i.m_stack) / value.m_fireworkItemCount) : 0);
		}

		internal List<PreviewRow> Preview(Player player, int rune, int preset = 0)
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			List<PreviewRow> list = new List<PreviewRow>();
			int num = 0;
			FireworkPiece[] array = (from f in All
				where Object.op_Implicit((Object)(object)f) && f.Ready && f.Kind < 2 && f.Settings.Rune == rune && Vector3.Distance(((Component)f).transform.position, ((Component)this).transform.position) <= 40f && Access(player, ((Component)f).transform.position)
				orderby Vector3.Distance(((Component)f).transform.position, ((Component)this).transform.position)
				select f).ThenBy<FireworkPiece, string>((FireworkPiece f) => ((object)Unsafe.As<ZDOID, ZDOID>(ref f.Data.m_uid)/*cast due to .constrained prefix*/).ToString(), StringComparer.Ordinal).ToArray();
			int count = Math.Min(16, array.Count((FireworkPiece f) => f.Settings.Valid && !f.Running && !f.box.IsInUse() && f.AvailableShots() > 0));
			FireworkPiece[] array2 = array;
			foreach (FireworkPiece fireworkPiece in array2)
			{
				ShowSettings settings = fireworkPiece.Settings;
				PreviewRow previewRow = new PreviewRow
				{
					Name = fireworkPiece.Label + " / " + VikingRocket.PatternName(settings.Pattern),
					Distance = Vector3.Distance(((Component)fireworkPiece).transform.position, ((Component)this).transform.position),
					Planned = settings.Shots,
					Delay = settings.Delay,
					Interval = settings.Interval,
					Available = fireworkPiece.AvailableShots()
				};
				previewRow.Status = ((!settings.Valid) ? "Invalid arrangement" : (fireworkPiece.Running ? "Already firing" : (fireworkPiece.box.IsInUse() ? "Box open" : ((previewRow.Available == 0) ? "No fireworks" : ((num >= 16) ? "Beyond 16-launcher limit" : "Ready")))));
				previewRow.Included = previewRow.Status == "Ready";
				if (previewRow.Included)
				{
					ShowSettings showSettings = PlannedFor(fireworkPiece, num, count, preset);
					previewRow.Planned = showSettings.Shots;
					previewRow.Delay = showSettings.Delay;
					previewRow.Interval = showSettings.Interval;
					if (preset != 0)
					{
						previewRow.Name = fireworkPiece.Label + " / Vanilla";
					}
					num++;
				}
				list.Add(previewRow);
			}
			return list;
		}

		private unsafe void OnRequest(long sender, ZPackage pkg)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0533: Unknown result type (might be due to invalid IL or missing references)
			//IL_0538: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready || !View.IsOwner())
			{
				Plugin.Note("Request ignored: not authoritative owner");
				return;
			}
			try
			{
				ZDOID id = pkg.ReadZDOID();
				long num = pkg.ReadLong();
				int num2 = pkg.ReadInt();
				Player player = Actor(id, sender);
				if (!Object.op_Implicit((Object)(object)player) || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 8f || !Access(player, ((Component)this).transform.position) || !ShowRules.Fresh(Now, num, Data.GetLong("SF_request", 0L)))
				{
					Plugin.Note("Request rejected: actor=" + Object.op_Implicit((Object)(object)player) + " sender=" + sender + " action=" + num2 + " now=" + Now + " issued=" + num + " prior=" + Data.GetLong("SF_request", 0L));
					return;
				}
				Data.Set("SF_request", num);
				if (num2 == 2)
				{
					Stop();
				}
				else
				{
					if (Running)
					{
						return;
					}
					switch (num2)
					{
					case 0:
					{
						ShowSettings showSettings = new ShowSettings
						{
							Rune = pkg.ReadInt(),
							Delay = pkg.ReadSingle(),
							Interval = pkg.ReadSingle(),
							Shots = pkg.ReadInt(),
							Fuse = pkg.ReadSingle(),
							Pattern = pkg.ReadInt(),
							Spread = pkg.ReadInt(),
							Preset = pkg.ReadInt()
						};
						if (showSettings.Valid)
						{
							Data.Set("SF_spread", (Kind == 1) ? showSettings.Spread : 0);
							Data.Set("SF_preset", (Kind == 2) ? showSettings.Preset : 0);
							Data.Set("SF_pattern", showSettings.Pattern);
							Data.Set("SF_rune", showSettings.Rune);
							Data.Set("SF_delay", showSettings.Delay);
							Data.Set("SF_interval", showSettings.Interval);
							Data.Set("SF_shots", showSettings.Shots);
							Data.Set("SF_fuse", showSettings.Fuse);
							ZDOID uid = Data.m_uid;
							Plugin.Note("Settings carved on " + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString());
						}
						break;
					}
					case 1:
						if (HasTorch(player))
						{
							if (!Settings.Valid)
							{
								Notice(sender, 5);
								break;
							}
							actorId = id;
							actorPeer = sender;
							if (Kind == 2)
							{
								if (All.Any((FireworkPiece f) => Object.op_Implicit((Object)(object)f) && (Object)(object)f != (Object)(object)this && f.Ready && f.Kind == 2 && f.Running && f.Settings.Rune == Settings.Rune && Vector3.Distance(((Component)f).transform.position, ((Component)this).transform.position) <= 80f))
								{
									Notice(sender, 2);
									break;
								}
								targets = (from f in All
									where Object.op_Implicit((Object)(object)f) && f.Ready && f.Kind < 2 && f.Settings.Valid && f.Settings.Rune == Settings.Rune && Vector3.Distance(((Component)f).transform.position, ((Component)this).transform.position) <= 40f && !f.Running && Access(player, ((Component)f).transform.position) && Object.op_Implicit((Object)(object)f.box) && !f.box.IsInUse() && f.NextAmmo() != null
									orderby Vector3.Distance(((Component)f).transform.position, ((Component)this).transform.position)
									select f).ThenBy<FireworkPiece, string>((FireworkPiece f) => ((object)Unsafe.As<ZDOID, ZDOID>(ref f.Data.m_uid)/*cast due to .constrained prefix*/).ToString(), StringComparer.Ordinal).Take(16).ToList();
								if (targets.Count == 0)
								{
									Notice(sender, 1);
									break;
								}
								showDuration = (from s in targets.Select((FireworkPiece t, int i) => PlannedFor(t, i, targets.Count, Settings.Preset))
									select (double)s.Delay + (double)((float)(s.Shots - 1) * s.Interval)).Max() + 2.0;
							}
							else
							{
								if (box.IsInUse())
								{
									Notice(sender, 3);
									break;
								}
								if (NextAmmo() == null)
								{
									Notice(sender, 4);
									break;
								}
							}
							long num3 = Now + (long)(Settings.Fuse * 10000000f);
							SetRunSettings(Settings);
							Data.Set("SF_beat", Now);
							Data.Set("SF_cursor", 0);
							Data.Set("SF_start", num3);
							Data.Set("SF_controller", ZDOID.None);
							Data.Set("SF_lastRun", num3);
							string[] obj = new string[6] { "Fuse lit: ", Label, " ", null, null, null };
							ZDOID uid = Data.m_uid;
							obj[3] = ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
							obj[4] = " start=";
							obj[5] = num3.ToString();
							Plugin.Note(string.Concat(obj));
							if (Kind == 2)
							{
								ArmTargets();
							}
							break;
						}
						goto default;
					default:
						Plugin.Note("Ignition requires equipped torch");
						break;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Note("Rejected malformed show request: " + ex.GetType().Name);
			}
		}

		private void ArmTargets()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_003a: 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)
			if (targets == null)
			{
				return;
			}
			for (int i = 0; i < targets.Count; i++)
			{
				FireworkPiece fireworkPiece = targets[i];
				if (Object.op_Implicit((Object)(object)fireworkPiece) && fireworkPiece.Ready)
				{
					ZPackage val = new ZPackage();
					val.Write(Data.m_uid);
					val.Write(actorId);
					val.Write(actorPeer);
					val.Write(StartTime);
					val.Write(i);
					val.Write(targets.Count);
					fireworkPiece.View.InvokeRPC("Skyforge_Arm_2", new object[1] { val });
				}
			}
		}

		private static FireworkPiece Find(ZDOID id)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			ZNetScene instance = ZNetScene.instance;
			if (instance == null)
			{
				return null;
			}
			GameObject obj = instance.FindInstance(id);
			if (obj == null)
			{
				return null;
			}
			return obj.GetComponent<FireworkPiece>();
		}

		private void OnArm(long sender, ZPackage p)
		{
			//IL_0029: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready || !View.IsOwner() || Kind == 2 || Running)
			{
				return;
			}
			try
			{
				FireworkPiece fireworkPiece = Find(p.ReadZDOID());
				Player player = Actor(p.ReadZDOID(), p.ReadLong());
				long num = p.ReadLong();
				int num2 = p.ReadInt();
				int num3 = p.ReadInt();
				if (num2 >= 0 && num3 >= 1 && num3 <= 16 && num2 < num3 && Object.op_Implicit((Object)(object)fireworkPiece) && fireworkPiece.Ready && fireworkPiece.Kind == 2 && fireworkPiece.Data.GetOwner() == sender && fireworkPiece.StartTime == num && num > Now + 10000000 && num <= Now + 160000000 && Data.GetLong("SF_lastRun", 0L) < num && fireworkPiece.Settings.Rune == Settings.Rune && !(Vector3.Distance(((Component)this).transform.position, ((Component)fireworkPiece).transform.position) > 40f) && Access(player, ((Component)this).transform.position) && Access(player, ((Component)fireworkPiece).transform.position) && !box.IsInUse() && NextAmmo() != null)
				{
					ShowSettings showSettings = fireworkPiece.PlannedFor(this, num2, num3, fireworkPiece.Settings.Preset);
					if (showSettings.Valid)
					{
						SetRunSettings(showSettings);
						Data.Set("SF_controller", fireworkPiece.Data.m_uid);
						Data.Set("SF_cursor", 0);
						Data.Set("SF_lastRun", num);
						Data.Set("SF_start", num);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Note("Rejected malformed arm request: " + ex.GetType().Name);
			}
		}

		private void Stop()
		{
			if (Ready && View.IsOwner())
			{
				Data.Set("SF_start", 0L);
				Data.Set("SF_cursor", 0);
				Data.Set("SF_runPlan", false);
			}
			targets = null;
		}

		private void Update()
		{
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)fuse))
			{
				fuse.SetBurning(Running && Now < StartTime, (float)Math.Max(0.0, (double)(StartTime - Now) / 10000000.0));
			}
			bool flag = View.IsOwner();
			if (flag != wasOwner)
			{
				wasOwner = flag;
				if (flag)
				{
					Stop();
				}
			}
			if (!flag || !Running || Time.unscaledTime < nextTick)
			{
				return;
			}
			nextTick = Time.unscaledTime + 0.05f;
			long now = Now;
			long start = StartTime;
			if (Kind == 2)
			{
				if (targets == null)
				{
					Stop();
					return;
				}
				if (now - Data.GetLong("SF_beat", 0L) > 5000000)
				{
					Data.Set("SF_beat", now);
					if (now < start - 10000000)
					{
						ArmTargets();
					}
				}
				foreach (FireworkPiece item in targets.Where((FireworkPiece t) => Object.op_Implicit((Object)(object)t) && t.Ready && t.StartTime == start && t.Data.GetZDOID("SF_controller") == Data.m_uid))
				{
					ShowSettings runSettings = item.RunSettings;
					if (runSettings.Valid)
					{
						showDuration = Math.Max(showDuration, runSettings.Delay + (float)(runSettings.Shots - 1) * runSettings.Interval + 2f);
					}
				}
				double num = showDuration;
				if ((double)now > (double)start + num * 10000000.0)
				{
					Stop();
				}
				return;
			}
			ZDOID zDOID = Data.GetZDOID("SF_controller");
			if (zDOID != ZDOID.None)
			{
				FireworkPiece fireworkPiece = Find(zDOID);
				if (!Object.op_Implicit((Object)(object)fireworkPiece) || !fireworkPiece.Ready || fireworkPiece.StartTime != start || now - fireworkPiece.Data.GetLong("SF_beat", 0L) > 30000000)
				{
					Stop();
					return;
				}
			}
			ShowSettings runSettings2 = RunSettings;
			int num2 = Data.GetInt("SF_cursor", 0);
			if (!runSettings2.Valid || num2 >= runSettings2.Shots || box.IsInUse())
			{
				Stop();
				return;
			}
			long num3 = runSettings2.Due(start, num2);
			if (now >= num3)
			{
				Data.Set("SF_cursor", num2 + 1);
				if (!ShowRules.Expired(now, num3))
				{
					Launch();
				}
			}
		}

		private ItemData NextAmmo()
		{
			if (!Object.op_Implicit((Object)(object)box) || box.GetInventory() == null)
			{
				return null;
			}
			if (!box.IsInUse())
			{
				AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null).Invoke(box, null);
			}
			Inventory inv = box.GetInventory();
			FireworkItem value;
			return ((IEnumerable<ItemData>)(from i in inv.GetAllItems()
				orderby i.m_gridPos.y, i.m_gridPos.x
				select i)).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => Plugin.Ammunition.TryGetValue(i.m_shared.m_name, out value) && inv.CountItems(i.m_shared.m_name, -1, true) >= value.m_fireworkItemCount));
		}

		private unsafe void Launch()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: 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)
			ItemData val = NextAmmo();
			if (val == null)
			{
				Stop();
				return;
			}
			FireworkItem val2 = Plugin.Ammunition[val.m_shared.m_name];
			box.GetInventory().RemoveItem(val.m_shared.m_name, val2.m_fireworkItemCount, -1, true);
			try
			{
				int num = Data.GetInt("SF_cursor", 1) - 1;
				ShowSettings runSettings = RunSettings;
				int num2 = runSettings.BurstAt(num);
				LaunchSpread.Offset((Kind == 1) ? runSettings.Spread : 0, num, (int)StartTime ^ StringExtensionMethods.GetStableHashCode(((object)Unsafe.As<ZDOID, ZDOID>(ref Data.m_uid)/*cast due to .constrained prefix*/).ToString()), out var x, out var z);
				Quaternion val3 = Quaternion.Euler(0f, ((Component)this).transform.eulerAngles.y, 0f);
				? val4;
				if (Kind != 1 || runSettings.Spread == 0)
				{
					val4 = ((num2 == 0) ? Quaternion.identity : ((Component)this).transform.rotation);
				}
				else
				{
					Vector3 up = Vector3.up;
					Vector3 val5 = new Vector3(x, 1f, z);
					val4 = val3 * Quaternion.FromToRotation(up, ((Vector3)(ref val5)).normalized);
				}
				Quaternion val6 = (Quaternion)val4;
				Vector3 val7 = ((Component)this).transform.position + Vector3.up * 1.4f + ((Kind == 1 && runSettings.Spread != 0) ? (val3 * new Vector3((float)(num % 5 - 2) * 0.22f, 0f, 0f)) : Vector3.zero);
				GameObject[] array = (GameObject[])((num2 == 0) ? ((Array)val2.m_fireworksEffects.Create(val7, val6, (Transform)null, 1f, -1, default(ZDOID))) : ((Array)new GameObject[1] { Object.Instantiate<GameObject>(VikingRocket.Prefabs[num2], val7, val6) }));
				string[] obj = new string[10] { "LAUNCH ", null, null, null, null, null, null, null, null, null };
				ZDOID uid = Data.m_uid;
				obj[1] = ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
				obj[2] = " shot=";
				obj[3] = Data.GetInt("SF_cursor", 0).ToString();
				obj[4] = " item=";
				obj[5] = ((Object)val2.m_fireworkItem).name;
				obj[6] = " effects=";
				obj[7] = array.Length.ToString();
				obj[8] = " networkTicks=";
				obj[9] = Now.ToString();
				Plugin.Note(string.Concat(obj));
			}
			catch (Exception ex)
			{
				Stop();
				Plugin.Note("Launch stopped after effect error: " + ex);
			}
		}
	}
	public static class FuseAudio
	{
		public static float[] Create(int rate = 22050, int seconds = 4)
		{
			float[] array = new float[rate * seconds];
			Random random = new Random(1731);
			double num = 0.0;
			double num2 = 0.0;
			int num3 = Math.Max(1, rate / 100);
			for (int i = 0; i < array.Length; i++)
			{
				double num4 = random.NextDouble() * 2.0 - 1.0;
				num = 0.84 * num + 0.16 * num4;
				if (random.NextDouble() < 13.0 / (double)rate)
				{
					num2 = (0.15 + random.NextDouble() * 0.3) * (double)((random.Next(2) != 0) ? 1 : (-1));
				}
				num2 *= 0.985;
				double num5 = Math.Min(1.0, Math.Min((double)i / (double)num3, (double)(array.Length - 1 - i) / (double)num3));
				array[i] = (float)Math.Max(-0.6, Math.Min(0.6, ((num4 - num) * 0.14 + num * 0.13 + num2) * num5));
			}
			return array;
		}
	}
	public sealed class FuseVisual : MonoBehaviour
	{
		private GameObject ember;

		private Light glow;

		private ParticleSystem sparks;

		private AudioSource sound;

		private static AudioClip clip;

		private bool burning;

		private float burnDuration;

		private void Ensure()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ember))
			{
				ember = new GameObject("Burning fuse ember");
				ember.transform.SetParent(((Component)this).transform, false);
				ember.transform.localPosition = new Vector3(0f, 0.85f, -0.27f);
				glow = ember.AddComponent<Light>();
				glow.color = new Color(1f, 0.46f, 0.08f);
				glow.range = 2f;
				glow.intensity = 0.5f;
				sparks = ember.AddComponent<ParticleSystem>();
				MainModule main = sparks.main;
				((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.28f);
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0.65f);
				((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.035f);
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(1f, 0.65f, 0.12f));
				((MainModule)(ref main)).maxParticles = 40;
				((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
				if (Object.op_Implicit((Object)(object)Plugin.SparkMaterial))
				{
					((Renderer)((Component)sparks).GetComponent<ParticleSystemRenderer>()).sharedMaterial = Plugin.SparkMaterial;
				}
				else
				{
					((Renderer)((Component)sparks).GetComponent<ParticleSystemRenderer>()).enabled = false;
				}
				EmissionModule emission = sparks.emission;
				((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(25f);
				ShapeModule shape = sparks.shape;
				((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4;
				((ShapeModule)(ref shape)).angle = 35f;
				((ShapeModule)(ref shape)).radius = 0.015f;
				((Component)sparks).transform.localRotation = Quaternion.Euler(-90f, 0f, 0f);
				GameObject val = new GameObject("Hemp fuse sizzle");
				val.transform.SetParent(((Component)this).transform, false);
				val.transform.localPosition = ember.transform.localPosition;
				sound = val.AddComponent<AudioSource>();
				sound.spatialBlend = 1f;
				sound.minDistance = 1f;
				sound.maxDistance = 12f;
				sound.rolloffMode = (AudioRolloffMode)1;
				sound.loop = true;
				sound.volume = 0f;
				sound.outputAudioMixerGroup = Plugin.EffectsMixer;
				if (!Object.op_Implicit((Object)(object)clip))
				{
					float[] array = FuseAudio.Create();
					clip = AudioClip.Create("Hemp fuse sizzle", array.Length, 1, 22050, false);
					typeof(AudioClip).GetMethod("SetData", new Type[2]
					{
						typeof(float[]),
						typeof(int)
					}).Invoke(clip, new object[2] { array, 0 });
				}
				sound.clip = clip;
			}
		}

		public void SetBurning(bool value, float remaining)
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			if (!value && !Object.op_Implicit((Object)(object)ember))
			{
				return;
			}
			Ensure();
			if (value != burning)
			{
				burning = value;
				ember.SetActive(value);
				if (value)
				{
					burnDuration = Mathf.Max(0.1f, remaining);
					sparks.Play();
					sound.Play();
				}
			}
			sound.volume = Mathf.MoveTowards(sound.volume, value ? 0.14f : 0f, Time.unscaledDeltaTime * 0.7f);
			if (!value && sound.volume <= 0f && sound.isPlaying)
			{
				sound.Stop();
			}
			if (value)
			{
				float num = Mathf.Clamp01(remaining / burnDuration);
				ember.transform.localPosition = new Vector3(num * 0.45f - 0.225f, 0.85f, -0.27f);
				glow.intensity = 0.4f + Mathf.Sin(Time.time * 37f) * 0.12f;
				sound.pitch = 1.02f - num * 0.1f;
			}
		}

		internal static void Dispose()
		{
			if (Object.op_Implicit((Object)(object)clip))
			{
				Object.Destroy((Object)(object)clip);
			}
			clip = null;
		}
	}
	public static class LaunchSpread
	{
		public static void Offset(int mode, int slot, int seed, out float x, out float z)
		{
			if (mode < 0 || mode > 2)
			{
				throw new ArgumentOutOfRangeException("mode");
			}
			if (slot < 0)
			{
				throw new ArgumentOutOfRangeException("slot");
			}
			x = (z = 0f);
			switch (mode)
			{
			case 0:
				return;
			case 1:
				x = (float)Math.Tan((double)(slot % 5 - 2) * 12.0 * Math.PI / 180.0);
				return;
			}
			uint num = (uint)(seed + slot * -1640531527);
			double num2 = Unit(Mix(num ^ 0xA511E9B3u)) * Math.PI * 2.0;
			double num3 = Math.Tan((8.0 + Unit(Mix(num ^ 0x63D83595)) * 17.0) * Math.PI / 180.0);
			x = (float)(Math.Cos(num2) * num3);
			z = (float)(Math.Sin(num2) * num3);
		}

		private static double Unit(uint value)
		{
			return (double)value / 4294967296.0;
		}

		private static uint Mix(uint value)
		{
			value ^= value >> 16;
			value *= 2146121005;
			value ^= value >> 15;
			value *= 2221713035u;
			value ^= value >> 16;
			return value;
		}
	}
	[BepInPlugin("SmeagsMods.SkyforgeFireworks", "Skyforge Fireworks", "0.6.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class Register
		{
			private static void Postfix(ZNetScene __instance, Dictionary<int, GameObject> ___m_namedPrefabs)
			{
				//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d2: Expected O, but got Unknown
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0234: Unknown result type (might be due to invalid IL or missing references)
				//IL_0239: Unknown result type (might be due to invalid IL or missing references)
				//IL_023b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0326: Unknown result type (might be due to invalid IL or missing references)
				//IL_032c: Expected O, but got Unknown
				//IL_024d: Unknown result type (might be due to invalid IL or missing references)
				//IL_025a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0270: 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_029d: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
				Prefabs.Clear();
				Ammunition.Clear();
				GameObject prefab = __instance.GetPrefab("fire_pit");
				Fireplace val = ((prefab != null) ? prefab.GetComponent<Fireplace>() : null);
				if ((Object)(object)val == (Object)null)
				{
					Note("No campfire effect catalog; registration stopped.");
					return;
				}
				TimberMaterial = (__instance.GetPrefab("wood_pole") ?? __instance.GetPrefab("piece_chest_wood")).GetComponentsInChildren<MeshRenderer>(true).SelectMany((MeshRenderer r) => ((Renderer)r).sharedMaterials).First((Material m) => Object.op_Implicit((Object)(object)m) && ((Object)m).name.IndexOf("wood", StringComparison.OrdinalIgnoreCase) >= 0 && ((Object)m.shader).name.IndexOf("Snow", StringComparison.OrdinalIgnoreCase) < 0);
				if (Object.op_Implicit((Object)(object)FuseMaterial))
				{
					Object.Destroy((Object)(object)FuseMaterial);
				}
				FuseMaterial = new Material(TimberMaterial);
				if (FuseMaterial.HasProperty("_Color"))
				{
					FuseMaterial.SetColor("_Color", new Color(0.72f, 0.54f, 0.28f));
				}
				SparkMaterial = (from r in ((Component)val).GetComponentsInChildren<ParticleSystemRenderer>(true)
					where Object.op_Implicit((Object)(object)((Renderer)r).sharedMaterial)
					select ((Renderer)r).sharedMaterial).FirstOrDefault();
				GameObject prefab2 = __instance.GetPrefab("sfx_firework_explode");
				object effectsMixer;
				if (prefab2 == null)
				{
					effectsMixer = null;
				}
				else
				{
					AudioSource component = prefab2.GetComponent<AudioSource>();
					effectsMixer = ((component != null) ? component.outputAudioMixerGroup : null);
				}
				EffectsMixer = (AudioMixerGroup)effectsMixer;
				if (!Object.op_Implicit((Object)(object)EffectsMixer) && Object.op_Implicit((Object)(object)AudioMan.instance?.m_masterMixer))
				{
					EffectsMixer = AudioMan.instance.m_masterMixer.FindMatchingGroups("SFX").FirstOrDefault();
				}
				string[] obj = new string[6]
				{
					"Materials: wood=",
					((Object)TimberMaterial).name,
					" shader=",
					((Object)TimberMaterial.shader).name,
					" sparks=",
					null
				};
				Material sparkMaterial = SparkMaterial;
				obj[5] = ((sparkMaterial != null) ? ((Object)sparkMaterial).name : null);
				Note(string.Concat(obj));
				FireworkItem[] fireworkItemList = val.m_fireworkItemList;
				foreach (FireworkItem val2 in fireworkItemList)
				{
					if ((Object)(object)val2.m_fireworkItem != (Object)null && val2.m_fireworkItemCount > 0 && val2.m_fireworksEffects.HasEffects())
					{
						Ammunition[val2.m_fireworkItem.m_itemData.m_shared.m_name] = val2;
						string[] obj2 = new string[6]
						{
							"Ammo ",
							((Object)val2.m_fireworkItem).name,
							" x",
							null,
							null,
							null
						};
						int fireworkItemCount = val2.m_fireworkItemCount;
						obj2[3] = fireworkItemCount.ToString();
						obj2[4] = " -> ";
						obj2[5] = string.Join(",", val2.m_fireworksEffects.m_effectPrefabs.Select((EffectData e) => (!Object.op_Implicit((Object)(object)e.m_prefab)) ? "null" : ((Object)e.m_prefab).name));
						Note(string.Concat(obj2));
					}
				}
				GameObject val3 = new GameObject("Skyforge prefab storage");
				val3.SetActive(false);
				val3.transform.SetParent(((Component)__instance).transform, false);
				VikingRocket.Register(__instance, ___m_namedPrefabs, val3.transform);
				Make(__instance, ___m_namedPrefabs, val3.transform, "Skyforge_Stand", "Launch stand", 0);
				Make(__instance, ___m_namedPrefabs, val3.transform, "Skyforge_Rack", "Salvo rack", 1);
				Make(__instance, ___m_namedPrefabs, val3.transform, "Skyforge_FuseBoard", "Show fuse board", 2);
				AddToHammer();
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class HammerAwake
		{
			private static void Postfix()
			{
				AddToHammer();
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class HammerCopy
		{
			private static void Postfix()
			{
				AddToHammer();
			}
		}

		[HarmonyPatch(typeof(Container), "GetHoverText")]
		private static class ChestHover
		{
			private static void Postfix(Container __instance, ref string __result)
			{
				FireworkPiece component = ((Component)__instance).GetComponent<FireworkPiece>();
				if (Object.op_Implicit((Object)(object)component) && component.Ready)
				{
					__result = component.GetHoverText();
				}
			}
		}

		[HarmonyPatch(typeof(Container), "Interact")]
		private static class ChestInteract
		{
			private static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt, ref bool __result)
			{
				FireworkPiece component = ((Component)__instance).GetComponent<FireworkPiece>();
				if (!Object.op_Implicit((Object)(object)component) || !component.Ready)
				{
					return true;
				}
				if (component.Running || alt || FireworkPiece.HasTorch((Player)(object)((character is Player) ? character : null)))
				{
					__result = component.Interact(character, hold, alt);
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Container), "UseItem")]
		private static class ChestItem
		{
			private static bool Prefix(Container __instance, Humanoid user, ItemData item, ref bool __result)
			{
				FireworkPiece component = ((Component)__instance).GetComponent<FireworkPiece>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					return true;
				}
				__result = component.UseItem(user, item);
				return false;
			}
		}

		[HarmonyPatch(typeof(Container), "RPC_RequestOpen")]
		[HarmonyPatch(typeof(Container), "RPC_RequestStack")]
		[HarmonyPatch(typeof(Container), "RPC_RequestTakeAll")]
		private static class ChestLock
		{
			private static bool Prefix(Container __instance)
			{
				FireworkPiece component = ((Component)__instance).GetComponent<FireworkPiece>();
				if (component == null)
				{
					return true;
				}
				return !component.Running;
			}
		}

		public const string Id = "SmeagsMods.SkyforgeFireworks";

		internal static Plugin Instance;

		internal static readonly Dictionary<string, FireworkItem> Ammunition = new Dictionary<string, FireworkItem>();

		internal static readonly List<GameObject> Prefabs = new List<GameObject>();

		internal static Material TimberMaterial;

		internal static Material FuseMaterial;

		internal static Material SparkMaterial;

		internal static AudioMixerGroup EffectsMixer;

		private Harmony harmony;

		private ConfigEntry<string> savedCarving;

		internal static void Note(string text)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)text);
		}

		private void Awake()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			Instance = this;
			try
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
				savedCarving = ((BaseUnityPlugin)this).Config.Bind<string>("Carving", "RememberedLauncher", "", "Last remembered launcher plan for this local profile. Use Remember carving in game to replace it.");
				SettingsPanel.LoadCarving(savedCarving.Value);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not load remembered carving; fireworks remain available. " + ex.Message));
			}
			harmony = new Harmony("SmeagsMods.SkyforgeFireworks");
			harmony.PatchAll();
			Note("Private prototype 0.6.0. Matching mod required on all peers.");
		}

		internal bool SaveCarving(ShowSettings plan)
		{
			if (savedCarving == null)
			{
				return false;
			}
			try
			{
				savedCarving.Value = CarvingCodec.Encode(plan);
				((BaseUnityPlugin)this).Config.Save();
				return true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not save remembered carving; keeping it for this session. " + ex.Message));
				return false;
			}
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			SettingsPanel.Dispose();
			FuseVisual.Dispose();
			if (Object.op_Implicit((Object)(object)FuseMaterial))
			{
				Object.Destroy((Object)(object)FuseMaterial);
			}
		}

		private void OnGUI()
		{
			SettingsPanel.Draw();
		}

		private static void Make(ZNetScene scene, Dictionary<int, GameObject> named, Transform root, string id, string label, int kind)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = scene.GetPrefab("piece_chest_wood");
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				throw new InvalidOperationException("Missing vanilla construction template " + id);
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, root, false);
			((Object)val).name = id;
			Piece component = val.GetComponent<Piece>();
			component.m_name = label;
			component.m_description = ((kind == 2) ? "Match rune channels, then light the fuse with a torch. Nearby launchers follow their own timing." : "Load fireworks, set a rune and timing, then light a fuse. Unused ammunition stays in the box.");
			component.m_category = (PieceCategory)0;
			component.m_resources = (Requirement[])(object)new Requirement[2]
			{
				new Requirement
				{
					m_resItem = scene.GetPrefab("Wood").GetComponent<ItemDrop>(),
					m_amount = ((kind == 1) ? 15 : 8),
					m_recover = true
				},
				new Requirement
				{
					m_resItem = scene.GetPrefab("Resin").GetComponent<ItemDrop>(),
					m_amount = 2,
					m_recover = true
				}
			};
			Container component2 = val.GetComponent<Container>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				component2.m_name = label;
				component2.m_width = ((kind == 0) ? 2 : 4);
				component2.m_height = 2;
				component2.m_privacy = (PrivacySetting)2;
			}
			if (kind == 2)
			{
				Object.DestroyImmediate((Object)(object)component2);
				foreach (Transform item in val.transform)
				{
					((Component)item).gameObject.SetActive(false);
				}
				WearNTear component3 = val.GetComponent<WearNTear>();
				component3.m_new = null;
				component3.m_worn = null;
				component3.m_broken = null;
				component3.m_wet = null;
				component3.m_snow = null;
				component3.m_snowWorn = null;
				component3.m_snowBroken = null;
				Material timberMaterial = TimberMaterial;
				BuildPart(val.transform, (PrimitiveType)3, "Timber board", new Vector3(0f, 0.75f, 0f), new Vector3(1.25f, 0.8f, 0.16f), timberMaterial);
				BuildPart(val.transform, (PrimitiveType)3, "Left leg", new Vector3(-0.45f, 0.35f, 0f), new Vector3(0.14f, 0.7f, 0.14f), timberMaterial);
				BuildPart(val.transform, (PrimitiveType)3, "Right leg", new Vector3(0.45f, 0.35f, 0f), new Vector3(0.14f, 0.7f, 0.14f), timberMaterial);
			}
			else
			{
				Material timberMaterial2 = TimberMaterial;
				int num = ((kind == 0) ? 1 : 5);
				for (int i = 0; i < num; i++)
				{
					BuildPart(val.transform, (PrimitiveType)2, "Launch tube", new Vector3(((float)i - (float)(num - 1) * 0.5f) * 0.22f, 0.9f, 0f), new Vector3(0.17f, 0.42f, 0.17f), timberMaterial2);
				}
			}
			BuildPart(val.transform, (PrimitiveType)2, "Hemp fuse", new Vector3(0f, 0.85f, -0.25f), new Vector3(0.035f, 0.28f, 0.035f), FuseMaterial).transform.localRotation = Quaternion.Euler(0f, 0f, 90f);
			val.AddComponent<FireworkPiece>().Kind = kind;
			val.SetActive(true);
			Prefabs.Add(val);
			scene.m_prefabs.Add(val);
			named.Add(StringExtensionMethods.GetStableHashCode(id), val);
			Note("Registered " + id);
		}

		private static GameObject BuildPart(Transform parent, PrimitiveType type, string name, Vector3 at, Vector3 scale, Material material)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive(type);
			((Object)val).name = name;
			val.transform.SetParent(parent, false);
			val.transform.localPosition = at;
			val.transform.localScale = scale;
			val.layer = ((Component)parent).gameObject.layer;
			if (Object.op_Implicit((Object)(object)material))
			{
				val.GetComponent<Renderer>().sharedMaterial = material;
			}
			return val;
		}

		private static void AddToHammer()
		{
			ObjectDB instance = ObjectDB.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return;
			}
			GameObject itemPrefab = instance.GetItemPrefab("Hammer");
			PieceTable val = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			val.m_pieces.RemoveAll((GameObject p) => !Object.op_Implicit((Object)(object)p));
			foreach (GameObject prefab in Prefabs)
			{
				if (Object.op_Implicit((Object)(object)prefab) && !val.m_pieces.Contains(prefab))
				{
					val.m_pieces.Add(prefab);
				}
			}
		}
	}
	internal static class SettingsPanel
	{
		[HarmonyPatch(typeof(Player), "TakeInput")]
		private static class PlayerInput
		{
			private static void Postfix(ref bool __result)
			{
				if (Object.op_Implicit((Object)(object)Target) || Time.frameCount <= SuppressThrough)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerController), "TakeInput")]
		private static class ControllerInput
		{
			private static void Postfix(ref bool __result)
			{
				if (Object.op_Implicit((Object)(object)Target) || Time.frameCount <= SuppressThrough)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		private static class Cursor
		{
			private static bool Prefix()
			{
				if (!Object.op_Implicit((Object)(object)Target))
				{
					return true;
				}
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
				return false;
			}
		}

		internal static FireworkPiece Target;

		private static ShowSettings settings;

		private static bool recoveredInvalid;

		private static ShowSettings carving;

		private static GUIStyle panelStyle;

		private static GUIStyle textStyle;

		private static GUIStyle titleStyle;

		private static GUIStyle buttonStyle;

		private static Texture2D panelTexture;

		private static List<FireworkPiece.PreviewRow> preview;

		private static Vector2 scroll;

		private static Vector2 contentScroll;

		private static float refreshAt;

		private static int previewRune;

		private static int previewPreset;

		private static int stock;

		internal static int SuppressThrough;

		internal static bool CarvingSaved { get; private set; }

		internal static void Open(FireworkPiece piece)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Target = piece;
			settings = piece.Settings;
			recoveredInvalid = !settings.Valid;
			if (recoveredInvalid)
			{
				settings = new ShowSettings();
			}
			preview = null;
			refreshAt = 0f;
			scroll = (contentScroll = Vector2.zero);
		}

		internal static void LoadCarving(string text)
		{
			CarvingSaved = CarvingCodec.TryDecode(text, out carving);
			if (!CarvingSaved && !string.IsNullOrEmpty(text))
			{
				Plugin.Note("Ignored invalid remembered carving; use Remember carving to replace it.");
			}
		}

		internal static void Remember()
		{
			carving = settings.Copy();
			CarvingSaved = Plugin.Instance.SaveCarving(carving);
		}

		internal static void Recall()
		{
			if (carving != null)
			{
				settings = carving.Copy();
			}
		}

		internal static void Close()
		{
			Target = null;
			SuppressThrough = Time.frameCount + 2;
		}

		internal static void Dispose()
		{
			Close();
			carving = null;
			CarvingSaved = false;
			if (Object.op_Implicit((Object)(object)panelTexture))
			{
				Object.Destroy((Object)(object)panelTexture);
			}
			panelStyle = null;
		}

		private static void Styles()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_006a: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			if (panelStyle == null)
			{
				panelTexture = new Texture2D(1, 1);
				panelTexture.SetPixel(0, 0, new Color(0.1f, 0.065f, 0.035f, 1f));
				panelTexture.Apply();
				panelStyle = new GUIStyle(GUI.skin.box)
				{
					padding = new RectOffset(20, 20, 12, 12)
				};
				panelStyle.normal.background = panelTexture;
				textStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 18,
					wordWrap = true
				};
				textStyle.normal.textColor = new Color(0.92f, 0.87f, 0.76f);
				titleStyle = new GUIStyle(textStyle)
				{
					fontSize = 21,
					fontStyle = (FontStyle)1
				};
				titleStyle.normal.textColor = new Color(1f, 0.73f, 0.29f);
				buttonStyle = new GUIStyle(GUI.skin.button)
				{
					fontSize = 18
				};
			}
		}

		internal static void Draw()
		{
			//IL_0039: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Invalid comparison between Unknown and I4
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Invalid comparison between Unknown and I4
			//IL_0839: Unknown result type (might be due to invalid IL or missing references)
			//IL_0851: Unknown result type (might be due to invalid IL or missing references)
			//IL_0856: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Target))
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Target.Ready || Target.Running || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)Target).transform.position) > 8f)
			{
				Close();
				return;
			}
			if ((int)Event.current.type == 4 && (int)Event.current.keyCode == 27)
			{
				Event.current.Use();
				Close();
				return;
			}
			Styles();
			float num = Mathf.Min(700, Screen.width - 30);
			float num2 = Mathf.Min(660, Screen.height - 30);
			GUILayout.BeginArea(new Rect(((float)Screen.width - num) / 2f, ((float)Screen.height - num2) / 2f, num, num2), panelStyle);
			GUILayout.Space(8f);
			GUILayout.Label("SKYFORGE  /  " + Target.Label.ToUpperInvariant(), titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Arrange the show. Light its fuse with your torch.\nFine-tune time by 0.1s with - / +.", textStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(16f);
			contentScroll = GUILayout.BeginScrollView(contentScroll, Array.Empty<GUILayoutOption>());
			if (recoveredInvalid)
			{
				GUILayout.Label("Invalid saved arrangement. These are safe draft defaults; Carve settings repairs this piece, Leave unchanged preserves it.", textStyle, Array.Empty<GUILayoutOption>());
			}
			settings.Rune = Mathf.RoundToInt(Slider("Rune channel", settings.Rune, 1f, 8f, "0"));
			settings.Fuse = Slider((Target.Kind == 2) ? "Show fuse (seconds)" : "Standalone fuse (seconds)", settings.Fuse, 3f, 15f, "0.0");
			if (Target.Kind < 2)
			{
				GUILayout.Label("Rhythm carving - shots / interval", textStyle, Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Opening  4 / 2s", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
				{
					settings.ApplyRhythm(0);
				}
				if (GUILayout.Button("Volley  8 / 1s", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
				{
					settings.ApplyRhythm(1);
				}
				if (GUILayout.Button("Finale  12 / 0.5s", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
				{
					settings.ApplyRhythm(2);
				}
				GUILayout.EndHorizontal();
				settings.Delay = Slider("Delay after fuse (seconds)", settings.Delay, 0f, 30f, "0.0");
				settings.Interval = Slider("Between shots (seconds)", settings.Interval, 0.5f, 10f, "0.0");
				settings.Shots = Mathf.RoundToInt(Slider("Shots", settings.Shots, 1f, 24f, "0"));
				GUILayout.Label("Burst rune: " + VikingRocket.PatternName(settings.Pattern), textStyle, Array.Empty<GUILayoutOption>());
				settings.Pattern = GUILayout.Toolbar(settings.Pattern, new string[5] { "Vanilla", "Bifrost", "World tree", "Mjolnir", "Rune cycle" }, buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) });
				if (Target.Kind == 1)
				{
					GUILayout.Label("Launch direction", textStyle, Array.Empty<GUILayoutOption>());
					settings.Spread = GUILayout.Toolbar(settings.Spread, new string[3] { "Straight", "Fan", "Random scatter" }, buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) });
					GUILayout.Label((settings.Spread == 1) ? "Five tube positions sweep left to right across a 48-degree fan." : ((settings.Spread == 2) ? "Each shot scatters within 25 degrees of upright; no repeated single burst point." : "Classic upright launch. Fan and scatter spread the bursts across the sky."), textStyle, Array.Empty<GUILayoutOption>());
				}
				if (settings.Pattern == 4)
				{
					GUILayout.Label("Bifrost > World tree > Mjolnir, repeating from the first shot.", textStyle, Array.Empty<GUILayoutOption>());
				}
				if (Time.unscaledTime >= refreshAt)
				{
					stock = Target.AvailableShots();
					refreshAt = Time.unscaledTime + 0.5f;
				}
				int num3 = Mathf.Min(stock, settings.Shots);
				GUILayout.Label("Loaded for " + stock + " shots. This plan fires " + num3 + " / " + settings.Shots + ".\n" + ((num3 == 0) ? "Load fireworks before lighting the fuse." : ("Launches +" + (settings.Fuse + settings.Delay).ToString("0.0") + "s to +" + (settings.Fuse + settings.Delay + (float)(num3 - 1) * settings.Interval).ToString("0.0") + "s after lighting.")), textStyle, Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Remember carving", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
				{
					Remember();
				}
				GUI.enabled = carving != null;
				if (GUILayout.Button("Recall carving", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
				{
					Recall();
				}
				GUI.enabled = true;
				GUILayout.EndHorizontal();
				GUILayout.Label((carving == null) ? "Remember a launcher plan to reuse across game sessions." : (CarvingSaved ? "Carving saved in this profile. Recall previews it; Carve settings applies it." : "Carving remembered for this session only; could not save it. Recall previews it; Carve settings applies it."), textStyle, Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Label("Premade vanilla show", titleStyle, Array.Empty<GUILayoutOption>());
				settings.Preset = GUILayout.SelectionGrid(settings.Preset, Enumerable.Range(0, 6).Select(ShowPresets.Name).ToArray(), 2, buttonStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Label(ShowPresets.Description(settings.Preset), textStyle, Array.Empty<GUILayoutOption>());
				if (settings.Preset != 0)
				{
					GUILayout.Label("Uses only loaded vanilla fireworks. This run overrides shot timing/burst/direction, not your saved launcher arrangements. Carve settings selects the show; a torch starts it.", textStyle, Array.Empty<GUILayoutOption>());
				}
				if (preview == null || previewRune != settings.Rune || previewPreset != settings.Preset || Time.unscaledTime >= refreshAt)
				{
					preview = Target.Preview(localPlayer, settings.Rune, settings.Preset);
					previewRune = settings.Rune;
					previewPreset = settings.Preset;
					refreshAt = Time.unscaledTime + 0.5f;
				}
				GUILayout.Label(preview.Count((FireworkPiece.PreviewRow p) => p.Included) + " ready launchers / " + preview.Where((FireworkPiece.PreviewRow p) => p.Included).Sum((FireworkPiece.PreviewRow p) => p.Shots) + " loaded shots", titleStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Label("Within 40m, up to 16. Times below are after lighting.\nPreview updates as ammunition changes.", textStyle, Array.Empty<GUILayoutOption>());
				scroll = GUILayout.BeginScrollView(scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(190f) });
				if (preview.Count == 0)
				{
					GUILayout.Label("No accessible launchers on this rune nearby.", textStyle, Array.Empty<GUILayoutOption>());
				}
				foreach (FireworkPiece.PreviewRow item in preview)
				{
					string text = (item.Included ? (item.Shots + " / " + item.Planned + " shots: +" + (settings.Fuse + item.Delay).ToString("0.0") + "s to +" + (settings.Fuse + item.Delay + (float)(item.Shots - 1) * item.Interval).ToString("0.0") + "s") : item.Status);
					GUILayout.Label(item.Name + " (" + item.Distance.ToString("0") + "m) - " + text, textStyle, Array.Empty<GUILayoutOption>());
				}
				GUILayout.EndScrollView();
			}
			GUILayout.EndScrollView();
			GUILayout.Space(8f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Carve settings", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(42f) }))
			{
				Target.Request(0, settings);
				Close();
			}
			if (GUILayout.Button("Leave unchanged", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(42f) }))
			{
				Close();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(8f);
			GUILayout.EndArea();
		}

		private static float Slider(string label, float value, float min, float max, string format)
		{
			float num = ((format == "0") ? 1f : 0.1f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUILayout.Label(value.ToString(format), textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(64f) });
			bool enabled = GUI.enabled;
			GUI.enabled = enabled && value > min;
			if (GUILayout.Button("-", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(32f),
				GUILayout.Height(28f)
			}))
			{
				value = Mathf.Clamp(value - num, min, max);
			}
			GUI.enabled = enabled && value < max;
			if (GUILayout.Button("+", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(32f),
				GUILayout.Height(28f)
			}))
			{
				value = Mathf.Clamp(value + num, min, max);
			}
			GUI.enabled = enabled;
			GUILayout.EndHorizontal();
			return Mathf.Round(GUILayout.HorizontalSlider(value, min, max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }) * 10f) / 10f;
		}
	}
	public static class ShowPresets
	{
		public static string Name(int preset)
		{
			return preset switch
			{
				0 => "Custom arrangement", 
				1 => "Hearthlight Welcome", 
				2 => "Fjord Echoes", 
				3 => "Northern Rain", 
				4 => "Viking Salute", 
				5 => "Grand Thing Finale", 
				_ => throw new ArgumentOutOfRangeException("preset"), 
			};
		}

		public static string Description(int preset)
		{
			return preset switch
			{
				0 => "Use each launcher's saved timing, burst and direction.", 
				1 => "Six gentle fan shots per launcher, two seconds apart, with a half-second ripple.", 
				2 => "Eight fan shots per launcher; paired launchers answer each other in staggered echoes.", 
				3 => "Ten scattered shots per launcher, one second apart, with a soft stagger.", 
				4 => "Twelve fan shots per launcher, three-quarter-second beats opening from the centre of the launcher order.", 
				5 => "Twenty-four scattered shots per launcher, half a second apart, in a tightly staggered finale.", 
				_ => throw new ArgumentOutOfRangeException("preset"), 
			};
		}

		public static ShowSettings Plan(int preset, int index, int count, ShowSettings original)
		{
			if (preset < 1 || preset > 5)
			{
				throw new ArgumentOutOfRangeException("preset");
			}
			if (count < 1 || count > 16)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			if (index < 0 || index >= count)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (original == null)
			{
				throw new ArgumentNullException("original");
			}
			if (!original.Valid)
			{
				throw new ArgumentException("Invalid source launcher settings", "original");
			}
			ShowSettings showSettings = original.Copy();
			showSettings.Pattern = 0;
			showSettings.Preset = 0;
			switch (preset)
			{
			case 1:
				showSettings.Shots = 6;
				showSettings.Interval = 2f;
				showSettings.Delay = (float)index * 0.5f;
				showSettings.Spread = 1;
				break;
			case 2:
				showSettings.Shots = 8;
				showSettings.Interval = 1.5f;
				showSettings.Delay = (float)(index % 2) * 0.75f + (float)(index / 2) * 0.25f;
				showSettings.Spread = 1;
				break;
			case 3:
				showSettings.Shots = 10;
				showSettings.Interval = 1f;
				showSettings.Delay = (float)index * 0.2f;
				showSettings.Spread = 2;
				break;
			case 4:
				showSettings.Shots = 12;
				showSettings.Interval = 0.75f;
				showSettings.Delay = Math.Abs((float)index - (float)(count - 1) * 0.5f) * 0.35f;
				showSettings.Spread = 1;
				break;
			case 5:
				showSettings.Shots = 24;
				showSettings.Interval = 0.5f;
				showSettings.Delay = (float)index * 0.1f;
				showSettings.Spread = 2;
				break;
			}
			return showSettings;
		}
	}
	public sealed class ShowSettings
	{
		public int Rune = 1;

		public int Shots = 6;

		public int Pattern;

		public int Spread;

		public int Preset;

		public float Delay;

		public float Interval = 1f;

		public float Fuse = 6f;

		public bool Valid
		{
			get
			{
				if (Spread >= 0 && Spread <= 2 && Preset >= 0 && Preset <= 5 && Pattern >= 0 && Pattern <= 4 && Rune >= 1 && Rune <= 8 && Shots >= 1 && Shots <= 24 && Finite(Delay) && Delay >= 0f && Delay <= 30f && Finite(Interval) && Interval >= 0.5f && Interval <= 10f && Finite(Fuse) && Fuse >= 3f)
				{
					return Fuse <= 15f;
				}
				return false;
			}
		}

		private static bool Finite(float n)
		{
			if (!float.IsNaN(n))
			{
				return !float.IsInfinity(n);
			}
			return false;
		}

		public long Due(long start, int index)
		{
			return start + (long)(((double)Delay + (double)index * (double)Interval) * 10000000.0);
		}

		public int BurstAt(int slot)
		{
			if (Pattern != 4)
			{
				return Pattern;
			}
			return 1 + Math.Max(0, slot) % 3;
		}

		public ShowSettings Copy()
		{
			return new ShowSettings
			{
				Rune = Rune,
				Shots = Shots,
				Pattern = Pattern,
				Spread = Spread,
				Preset = Preset,
				Delay = Delay,
				Interval = Interval,
				Fuse = Fuse
			};
		}

		public void ApplyRhythm(int rhythm)
		{
			if (rhythm < 0 || rhythm > 2)
			{
				throw new ArgumentOutOfRangeException("rhythm");
			}
			Shots = rhythm switch
			{
				1 => 8, 
				0 => 4, 
				_ => 12, 
			};
			Interval = rhythm switch
			{
				1 => 1f, 
				0 => 2f, 
				_ => 0.5f, 
			};
		}
	}
	public static class ShowRules
	{
		public const double LateTolerance = 0.25;

		public static bool Fresh(long now, long request, long previous)
		{
			if (request > previous && request <= now + 10000000)
			{
				return request >= now - 30000000;
			}
			return false;
		}

		public static bool Due(long now, long due)
		{
			if (now >= due)
			{
				return (double)(now - due) <= 2500000.0;
			}
			return false;
		}

		public static bool Expired(long now, long due)
		{
			return (double)(now - due) > 2500000.0;
		}
	}
	public sealed class VikingRocket : MonoBehaviour
	{
		internal static readonly Dictionary<int, GameObject> Prefabs = new Dictionary<int, GameObject>();

		internal static readonly HashSet<VikingRocket> Live = new HashSet<VikingRocket>();

		private static Material material;

		private static GameObject launchSound;

		private static GameObject burstSound;

		private const float Ascent = 2.8f;

		private const float Height = 40f;

		private const float Life = 8f;

		public int Pattern;

		private ZNetView view;

		private ParticleSystem trail;

		private ParticleSystem burst;

		private Light glow;

		private long birth;

		private bool launchSoundHandled;

		internal bool HasBurst { get; private set; }

		internal int EmittedParticles { get; private set; }

		internal static string PatternName(int pattern)
		{
			return pattern switch
			{
				4 => "Rune cycle", 
				3 => "Mjolnir", 
				2 => "World tree", 
				1 => "Bifrost", 
				_ => "Vanilla", 
			};
		}

		internal static void Register(ZNetScene scene, Dictionary<int, GameObject> named, Transform root)
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			Prefabs.Clear();
			if (Object.op_Implicit((Object)(object)material))
			{
				Object.Destroy((Object)(object)material);
			}
			ZSFX[] componentsInChildren = scene.GetPrefab("sfx_firework_explode").GetComponentsInChildren<ZSFX>(true);
			launchSound = SoundTemplate(((IEnumerable<ZSFX>)componentsInChildren).FirstOrDefault((Func<ZSFX, bool>)((ZSFX s) => s.m_maxDelay <= 0f)), root, "Skyforge launch sound");
			burstSound = SoundTemplate(((IEnumerable<ZSFX>)componentsInChildren.OrderByDescending((ZSFX s) => s.m_maxDelay)).FirstOrDefault((Func<ZSFX, bool>)((ZSFX s) => s.m_maxDelay > 0f)), root, "Skyforge burst sound");
			if (Object.op_Implicit((Object)(object)Plugin.SparkMaterial))
			{
				material = new Material(Plugin.SparkMaterial);
				if (material.HasProperty("_TintColor"))
				{
					material.SetColor("_TintColor", Color.white);
				}
				if (material.HasProperty("_Color"))
				{
					material.SetColor("_Color", Color.white);
				}
			}
			ZNetView component = scene.GetPrefab("vfx_Firework_Rocket").GetComponent<ZNetView>();
			for (int num = 1; num <= 3; num++)
			{
				string text = num switch
				{
					2 => "Skyforge_WorldTreeRocket", 
					1 => "Skyforge_BifrostRocket", 
					_ => "Skyforge_MjolnirRocket", 
				};
				GameObject val = new GameObject(text);
				val.transform.SetParent(root, false);
				ZNetView obj = val.AddComponent<ZNetView>();
				obj.m_persistent = false;
				obj.m_distant = true;
				obj.m_type = component.m_type;
				TimedDestruction obj2 = val.AddComponent<TimedDestruction>();
				obj2.m_timeout = 9f;
				obj2.m_triggerOnAwake = true;
				obj2.m_forceTakeOwnershipAndDestroy = true;
				val.AddComponent<VikingRocket>().Pattern = num;
				Prefabs.Add(num, val);
				scene.m_prefabs.Add(val);
				named.Add(StringExtensionMethods.GetStableHashCode(text), val);
			}
		}

		private static GameObject SoundTemplate(ZSFX source, Transform root, string name)
		{
			if (!Object.op_Implicit((Object)(object)source))
			{
				Plugin.Note("Missing native sound template: " + name);
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)source).gameObject, root, false);
			((Object)val).name = name;
			if (Object.op_Implicit((Object)(object)val.GetComponentInChildren<ZNetView>(true)))
			{
				Object.Destroy((Object)(object)val);
				Plugin.Note("Unexpected network sound child; skipped " + name);
				return null;
			}
			ZSFX[] componentsInChildren = val.GetComponentsInChildren<ZSFX>(true);
			foreach (ZSFX obj in componentsInChildren)
			{
				obj.m_minDelay = 0f;
				obj.m_maxDelay = 0f;
			}
			return val;
		}

		private void PlaySound(bool burstEvent)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (burstEvent ? burstSound : launchSound);
			if (Object.op_Implicit((Object)(object)val))
			{
				Object.Instantiate<GameObject>(val, ((Component)this).transform.position + ((Component)this).transform.up * (burstEvent ? 40f : 0f), Quaternion.identity, ((Component)this).transform);
			}
		}

		private void Start()
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			view = ((Component)this).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid())
			{
				((Behaviour)this).enabled = false;
				return;
			}
			if (view.IsOwner() && view.GetZDO().GetLong("SF_birth", 0L) == 0L)
			{
				view.GetZDO().Set("SF_birth", FireworkPiece.Now);
			}
			Live.Add(this);
			trail = Particles("Ascending spark", 0.65f, 0.12f, (Pattern == 2) ? new Color(0.35f, 1f, 0.3f) : new Color(0.5f, 0.8f, 1f));
			MainModule main = trail.main;
			((MainModule)(ref main)).loop = true;
			EmissionModule emission = trail.emission;
			((EmissionModule)(ref emission)).enabled = true;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(50f);
			glow = ((Component)trail).gameObject.AddComponent<Light>();
			glow.range = 3f;
			glow.intensity = 1.4f;
			glow.color = ((Pattern == 2) ? Color.green : Color.cyan);
		}

		private ParticleSystem Particles(string name, float lifetime, float size, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(((Component)this).transform, false);
			ParticleSystem val2 = val.AddComponent<ParticleSystem>();
			val2.Stop(true, (ParticleSystemStopBehavior)0);
			MainModule main = val2.main;
			((MainModule)(ref main)).playOnAwake = false;
			((MainModule)(ref main)).loop = false;
			((MainModule)(ref main)).duration = 4f;
			((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(lifetime);
			((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0f);
			((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(size);
			((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(color);
			((MainModule)(ref main)).maxParticles = 400;
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
			EmissionModule emission = val2.emission;
			((EmissionModule)(ref emission)).enabled = false;
			ShapeModule shape = val2.shape;
			((ShapeModule)(ref shape)).enabled = false;
			ParticleSystemRenderer component = ((Component)val2).GetComponent<ParticleSystemRenderer>();
			if (Object.op_Implicit((Object)(object)material))
			{
				((Renderer)component).sharedMaterial = material;
			}
			else
			{
				((Renderer)component).enabled = false;
			}
			ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime;
			((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true;
			Gradient val3 = new Gradient();
			val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
			{
				new GradientColorKey(Color.white, 0f),
				new GradientColorKey(Color.white, 1f)
			}, (GradientAlphaKey[])(object)new GradientAlphaKey[3]
			{
				new GradientAlphaKey(1f, 0f),
				new GradientAlphaKey(0.9f, 0.5f),
				new GradientAlphaKey(0f, 1f)
			});
			((ColorOverLifetimeModule)(ref colorOverLifetime)).color = MinMaxGradient.op_Implicit(val3);
			return val2;
		}

		private void Update()
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid())
			{
				return;
			}
			if (birth == 0L)
			{
				birth = view.GetZDO().GetLong("SF_birth", 0L);
			}
			if (birth == 0L)
			{
				return;
			}
			float num = Mathf.Max(0f, (float)((double)(FireworkPiece.Now - birth) / 10000000.0));
			if (!launchSoundHandled)
			{
				launchSoundHandled = true;
				if (num < 0.4f)
				{
					PlaySound(burstEvent: false);
				}
			}
			if (num > 8f)
			{
				if (view.IsOwner())
				{
					ZNetScene.instance.Destroy(((Component)this).gameObject);
				}
			}
			else if (num < 2.8f)
			{
				((Component)trail).transform.localPosition = Vector3.up * (40f * num / 2.8f);
				if (!trail.isPlaying)
				{
					trail.Play();
				}
				if (Pattern == 1)
				{
					MainModule main = trail.main;
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Color.HSVToRGB(num * 0.3f % 1f, 0.75f, 1f));
				}
			}
			else if (!HasBurst)
			{
				HasBurst = true;
				trail.Stop(true, (ParticleSystemStopBehavior)1);
				((Behaviour)glow).enabled = false;
				if (num < 5.8f)
				{
					Burst(num - 2.8f);
				}
				if (num < 3.2f)
				{
					PlaySound(burstEvent: true);
				}
			}
		}

		private void Emit(Vector3 velocity, Color color)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystem obj = burst;
			EmitParams val = default(EmitParams);
			((EmitParams)(ref val)).position = ((Component)this).transform.position + ((Component)this).transform.up * 40f;
			((EmitParams)(ref val)).velocity = ((Component)this).transform.rotation * velocity;
			((EmitParams)(ref val)).startColor = Color32.op_Implicit(color);
			((EmitParams)(ref val)).startLifetime = 3f;
			((EmitParams)(ref val)).startSize = ((Pattern == 3) ? 0.7f : 0.19f);
			obj.Emit(val, 1);
			EmittedParticles++;
		}

		private unsafe void Burst(float catchup)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: Unknown result type (might be due to invalid IL or missing references)
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Unknown result type (might be due to invalid IL or missing references)
			//IL_049a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			burst = Particles("Runic sky burst", 3f, 0.19f, Color.white);
			MainModule main = burst.main;
			((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0.08f);
			burst.Play();
			if (Pattern == 1)
			{
				for (int i = 0; i < 7; i++)
				{
					for (int j = 0; j < 28; j++)
					{
						float num = (float)j * (float)Math.PI * 2f / 28f;
						Vector3 val = new Vector3(Mathf.Cos(num), Mathf.Sin(num), Mathf.Cos(num) * (float)(i - 3) * 0.14f);
						Vector3 velocity = ((Vector3)(ref val)).normalized * (8f + (float)i * 0.5f);
						Emit(velocity, Color.HSVToRGB((float)i / 7f, 0.85f, 1f));
					}
				}
			}
			else if (Pattern == 2)
			{
				for (int k = 0; k < 30; k++)
				{
					Emit(new Vector3(0f, -8f + (float)k * 15f / 29f, 0f), new Color(1f, 0.75f, 0.22f));
				}
				for (int l = 0; l < 5; l++)
				{
					for (int m = 0; m < 6; m++)
					{
						for (int n = 1; n <= 8; n++)
						{
							float num2 = (9f - (float)l * 1.3f) * (float)n / 8f;
							float num3 = (float)m * (float)Math.PI / 3f;
							Emit(new Vector3(Mathf.Cos(num3) * num2, -5f + (float)l * 2.2f + (float)n * 0.25f, Mathf.Sin(num3) * num2), (n == 8) ? new Color(1f, 0.85f, 0.3f) : new Color(0.25f, 1f, 0.42f));
						}
					}
				}
			}
			else if (Pattern == 3)
			{
				Color color = default(Color);
				((Color)(ref color))..ctor(1f, 0.75f, 0.2f);
				Color color2 = default(Color);
				((Color)(ref color2))..ctor(0.4f, 0.8f, 1f);
				Stroke(new Vector3(-8f, 2f, 0f), new Vector3(8f, 2f, 0f), 20, color);
				Stroke(new Vector3(8f, 2f, 0f), new Vector3(8f, 7f, 0f), 20, color);
				Stroke(new Vector3(8f, 7f, 0f), new Vector3(-8f, 7f, 0f), 20, color);
				Stroke(new Vector3(-8f, 7f, 0f), new Vector3(-8f, 2f, 0f), 20, color);
				Stroke(new Vector3(-1f, -8f, 0f), new Vector3(-1f, 2f, 0f), 20, color);
				Stroke(new Vector3(1f, -8f, 0f), new Vector3(1f, 2f, 0f), 20, color);
				Stroke(new Vector3(-1f, -8f, 0f), new Vector3(1f, -8f, 0f), 20, color);
				Stroke(new Vector3(-8f, 4.5f, 0f), new Vector3(8f, 4.5f, 0f), 20, color);
				int[] array = new int[2] { -1, 1 };
				foreach (int num5 in array)
				{
					Stroke(new Vector3((float)(num5 * 10), 8f, 0f), new Vector3((float)(num5 * 12), 3f, 0f), 8, color2);
					Stroke(new Vector3((float)(num5 * 12), 3f, 0f), new Vector3((float)(num5 * 9), 3f, 0f), 8, color2);
					Stroke(new Vector3((float)(num5 * 9), 3f, 0f), new Vector3((float)(num5 * 11), -3f, 0f), 8, color2);
				}
			}
			if (catchup > 0f)
			{
				burst.Simulate(catchup, true, false, false);
				burst.Play();
			}
			string[] obj = new string[10]
			{
				"CUSTOM BURST ",
				PatternName(Pattern),
				" zdo=",
				null,
				null,
				null,
				null,
				null,
				null,
				null
			};
			ZDOID uid = view.GetZDO().m_uid;
			obj[3] = ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
			obj[4] = " particles=";
			obj[5] = EmittedParticles.ToString();
			obj[6] = " birth=";
			obj[7] = birth.ToString();
			obj[8] = " ticks=";
			obj[9] = FireworkPiece.Now.ToString();
			Plugin.Note(string.Concat(obj));
		}

		private void Stroke(Vector3 from, Vector3 to, int count, Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < count; i++)
			{
				Emit(Vector3.Lerp(from, to, (float)i / (float)(count - 1)), color);
			}
		}

		private void OnDestroy()
		{
			Live.Remove(this);
		}
	}
}