Decompiled source of PocketExpedition v0.0.3

BepInEx/plugins/PocketExpedition/PocketExpedition.dll

Decompiled a month ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PocketExpedition.Core;
using PocketExpedition.Runtime;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Networking;
using UnityEngine.UI;

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

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PocketExpedition
{
	[BepInPlugin("com.pocketexpedition.idlegame", "Pocket Expedition", "0.0.3")]
	[DefaultExecutionOrder(-32000)]
	public sealed class PocketExpeditionPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.pocketexpedition.idlegame";

		public const string PluginName = "Pocket Expedition";

		public const string PluginVersion = "0.0.3";

		private SaveRepository? saveRepository;

		private IdleGame? game;

		private PixelAssetLoader? assetLoader;

		private BundleAssetStore? assetBundle;

		private PocketAudio? audio;

		private PocketExpeditionView? view;

		private InputFocusController? inputFocus;

		private float refreshAccumulator;

		private float saveAccumulator;

		private bool f8WasHeld;

		private bool primaryPointerWasHeld;

		private bool applicationFocused = true;

		private bool applicationQuitting;

		private readonly OverlayInteractionState overlayInteraction = new OverlayInteractionState();

		private bool runtimeProbeLogged;

		private int inputProcessedFrame = -1;

		private string rankingServerUrl = "https://pocketexpedition.lotus030106.workers.dev";

		private void Awake()
		{
			rankingServerUrl = ((BaseUnityPlugin)this).Config.Bind<string>("Ranking", "ServerUrl", "https://pocketexpedition.lotus030106.workers.dev", "Pocket Expedition 온라인 랭킹 서버의 HTTPS 주소").Value.Trim();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Pocket Expedition 등록 완료 · Unity Start에서 에셋 초기화 예정");
		}

		private void Start()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Pocket Expedition Start 확인");
			try
			{
				string pluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Paths.PluginPath;
				saveRepository = new SaveRepository(Path.Combine(Paths.ConfigPath));
				bool recoveredFromBackup;
				GameState gameState = saveRepository.Load(out recoveredFromBackup);
				game = new IdleGame(gameState);
				OfflineReward reward = game.PrepareOfflineProgress(DateTimeOffset.UtcNow.ToUnixTimeSeconds());
				game.PersistState = saveRepository.Save;
				assetBundle = new BundleAssetStore(pluginDirectory, delegate(string message)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)message);
				});
				assetLoader = new PixelAssetLoader(assetBundle);
				assetLoader.Load(pluginDirectory, delegate(string message)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)message);
				});
				if (!assetLoader.IsComplete)
				{
					throw new InvalidDataException("AssetBundle is incomplete. Install the matching release files.");
				}
				audio = new PocketAudio(pluginDirectory, assetBundle, delegate(string message)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)message);
				});
				audio.SetVolume((float)gameState.SoundVolumePercent / 100f);
				audio.SetOverlayActive(active: false, gameState.SoundEnabled);
				inputFocus = new InputFocusController();
				inputFocus.BeforeHostInput = ProcessOverlayInput;
				view = new PocketExpeditionView(game, assetLoader, audio, CloseOverlay, saveRepository, RestoreSave, rankingServerUrl);
				view.PassiveInteractionRequested += EnterPassiveMode;
				if (reward.Seconds > 0 && reward.Gold > 0.0)
				{
					view.ShowOfflineReward(reward);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Pocket Expedition 0.0.3 준비 완료 · F8로 열기");
				if (recoveredFromBackup)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"기본 저장이 손상되어 백업 저장을 불러옴");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("초기화 실패: " + ex));
				DisposeRuntime();
			}
		}

		private void OnEnable()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Pocket Expedition OnEnable 확인");
		}

		private void Update()
		{
			if (!runtimeProbeLogged)
			{
				runtimeProbeLogged = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("런타임 Update 루프 확인 · game=" + (game != null) + " view=" + (view != null) + " inputFocus=" + (inputFocus != null) + " · InputSystem Keyboard=" + (Keyboard.current != null) + " · F8 대체 입력 활성화"));
			}
			if (game == null || view == null || inputFocus == null)
			{
				return;
			}
			audio?.SetExpeditionActive(game.SessionActive, game.State.ProfileId);
			audio?.Tick();
			ProcessOverlayInput();
			game.Tick(Time.unscaledDeltaTime);
			inputFocus.Tick();
			view.TickVisuals(Time.unscaledTime);
			view.ApplyModGraphics();
			refreshAccumulator += Time.unscaledDeltaTime;
			if (refreshAccumulator >= 0.1f)
			{
				refreshAccumulator = 0f;
				if (view.IsVisible)
				{
					view.Refresh();
				}
			}
			if (game.State.HasStarted && game.SessionActive)
			{
				saveAccumulator += Time.unscaledDeltaTime;
				if (saveAccumulator >= (float)game.State.AutoSaveIntervalSeconds)
				{
					saveAccumulator = 0f;
					SafeSave(snapshot: true);
				}
			}
		}

		private void ProcessOverlayInput()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (view == null || inputFocus == null || !applicationFocused || inputProcessedFrame == Time.frameCount)
			{
				return;
			}
			inputProcessedFrame = Time.frameCount;
			if (ReadF8Pressed())
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"F8 입력 감지 · 방치형 오버레이 전환");
				ToggleOverlay();
			}
			if (overlayInteraction.IsInteractive)
			{
				view.ProcessConfiguredKeys();
			}
			if (overlayInteraction.IsVisible && applicationFocused && ReadPrimaryPointerPressed())
			{
				OverlayInteractionMode mode = overlayInteraction.Mode;
				if (overlayInteraction.IsInteractive || (Cursor.visible && (int)Cursor.lockState == 0))
				{
					overlayInteraction.PointerPressed(view.IsPointerInsideWindow());
				}
				if (mode != overlayInteraction.Mode)
				{
					ApplyOverlayInteraction(mode == OverlayInteractionMode.Interactive);
				}
			}
		}

		private void LateUpdate()
		{
			inputFocus?.Tick();
			if (inputFocus != null && overlayInteraction.IsInteractive && applicationFocused)
			{
				inputFocus.EnsureOverlayCursor();
			}
		}

		private void OnApplicationQuit()
		{
			applicationQuitting = true;
			SafeSave();
		}

		private void OnDisable()
		{
			overlayInteraction.Hide();
			ApplyOverlayInteraction(deferGameplayRelease: false);
		}

		private void OnDestroy()
		{
			SafeSave();
			DisposeRuntime();
		}

		private bool ReadF8Pressed()
		{
			bool flag = false;
			try
			{
				flag = Keyboard.current != null && ((ButtonControl)Keyboard.current.f8Key).wasPressedThisFrame;
			}
			catch
			{
			}
			try
			{
				bool key = Input.GetKey((KeyCode)289);
				flag |= key && !f8WasHeld;
				f8WasHeld = key;
			}
			catch
			{
			}
			return flag;
		}

		private void OnApplicationFocus(bool focused)
		{
			applicationFocused = focused;
			overlayInteraction.SetApplicationFocus(focused);
			ApplyOverlayInteraction(deferGameplayRelease: false);
		}

		private bool ReadPrimaryPointerPressed()
		{
			bool flag = false;
			try
			{
				flag = Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame;
			}
			catch
			{
			}
			try
			{
				bool mouseButton = Input.GetMouseButton(0);
				flag |= mouseButton && !primaryPointerWasHeld;
				primaryPointerWasHeld = mouseButton;
			}
			catch
			{
			}
			return flag;
		}

		private bool ReadSkillPressed(int index)
		{
			bool flag = false;
			if (Keyboard.current != null)
			{
				try
				{
					switch (index)
					{
					case 0:
						flag = ((ButtonControl)Keyboard.current.digit1Key).wasPressedThisFrame || ((ButtonControl)Keyboard.current.numpad1Key).wasPressedThisFrame;
						break;
					case 1:
						flag = ((ButtonControl)Keyboard.current.digit2Key).wasPressedThisFrame || ((ButtonControl)Keyboard.current.numpad2Key).wasPressedThisFrame;
						break;
					case 2:
						flag = ((ButtonControl)Keyboard.current.digit3Key).wasPressedThisFrame || ((ButtonControl)Keyboard.current.numpad3Key).wasPressedThisFrame;
						break;
					case 3:
						flag = ((ButtonControl)Keyboard.current.digit4Key).wasPressedThisFrame || ((ButtonControl)Keyboard.current.numpad4Key).wasPressedThisFrame;
						break;
					}
				}
				catch
				{
				}
			}
			try
			{
				bool flag2 = flag;
				flag = (byte)((flag2 ? 1u : 0u) | (uint)(index switch
				{
					0 => (Input.GetKeyDown((KeyCode)49) || Input.GetKeyDown((KeyCode)257)) ? 1 : 0, 
					1 => (Input.GetKeyDown((KeyCode)50) || Input.GetKeyDown((KeyCode)258)) ? 1 : 0, 
					2 => (Input.GetKeyDown((KeyCode)51) || Input.GetKeyDown((KeyCode)259)) ? 1 : 0, 
					3 => (Input.GetKeyDown((KeyCode)52) || Input.GetKeyDown((KeyCode)260)) ? 1 : 0, 
					_ => 0, 
				})) != 0;
			}
			catch
			{
			}
			return flag;
		}

		private void ToggleOverlay()
		{
			if (view != null && inputFocus != null)
			{
				bool isVisible = overlayInteraction.IsVisible;
				overlayInteraction.ToggleF8();
				if (overlayInteraction.IsInteractive)
				{
					view.RestoreFromMinimized();
				}
				ApplyOverlayInteraction(deferGameplayRelease: false);
				if (!overlayInteraction.IsVisible)
				{
					SafeSave();
				}
				if (!isVisible && overlayInteraction.IsInteractive)
				{
					audio?.PlayPortal();
				}
			}
		}

		private void CloseOverlay()
		{
			overlayInteraction.Hide();
			ApplyOverlayInteraction(deferGameplayRelease: false);
			SafeSave();
		}

		private void EnterPassiveMode()
		{
			OverlayInteractionMode mode = overlayInteraction.Mode;
			overlayInteraction.RequestPassive();
			if (mode != overlayInteraction.Mode)
			{
				ApplyOverlayInteraction(deferGameplayRelease: false);
			}
		}

		private void ApplyOverlayInteraction(bool deferGameplayRelease)
		{
			if (view == null || inputFocus == null)
			{
				return;
			}
			if (applicationQuitting || !view.IsAlive)
			{
				inputFocus.ReleaseToGame();
				return;
			}
			view.SetVisible(overlayInteraction.IsVisible);
			audio?.SetOverlayActive(overlayInteraction.IsVisible, game?.State.SoundEnabled ?? true);
			if (overlayInteraction.IsInteractive && applicationFocused)
			{
				inputFocus.CaptureForOverlay();
				view.SetWindowInteraction(enabled: true);
				inputFocus.EnsureOverlayCursor();
				return;
			}
			view.SetWindowInteraction(enabled: false);
			if (deferGameplayRelease)
			{
				inputFocus.ReleaseAfterPointerFrame();
			}
			else
			{
				inputFocus.ReleaseToGame();
			}
		}

		private void RestoreSave(string key)
		{
			if (saveRepository != null && game != null && assetLoader != null && audio != null)
			{
				if (game.RewardSettlementPending || game.ActiveSpecial != SpecialDungeon.None)
				{
					throw new InvalidOperationException("먼저 특수 던전과 보상 정산을 완료해 주세요.");
				}
				GameState gameState = saveRepository.ReadSnapshot(key);
				GameState state = game.State;
				gameState.LanguageCode = state.LanguageCode;
				gameState.EnglishUi = state.EnglishUi;
				gameState.SoundEnabled = state.SoundEnabled;
				gameState.SoundVolumePercent = state.SoundVolumePercent;
				gameState.UiScalePercent = state.UiScalePercent;
				gameState.ReduceMotion = state.ReduceMotion;
				gameState.AutoSaveIntervalSeconds = state.AutoSaveIntervalSeconds;
				gameState.RankingOrigin = new RankingOrigin
				{
					SourceProfileId = gameState.ProfileId,
					SourceRevision = gameState.SaveRevision
				};
				gameState.ProfileId = Guid.NewGuid().ToString("N");
				gameState.SaveRevision = 0L;
				gameState.RankingPreferences = new RankingPreferences
				{
					OptIn = state.RankingPreferences.OptIn
				};
				IdleGame idleGame = new IdleGame(gameState);
				idleGame.Continue();
				idleGame.PersistState = saveRepository.Save;
				if (game.State.HasStarted && game.SessionActive)
				{
					saveRepository.CreateSnapshot(game.State, SaveKind.BeforeRestore);
				}
				PocketExpeditionView pocketExpeditionView = new PocketExpeditionView(idleGame, assetLoader, audio, CloseOverlay, saveRepository, RestoreSave, rankingServerUrl);
				pocketExpeditionView.PassiveInteractionRequested += EnterPassiveMode;
				try
				{
					saveRepository.Save(gameState);
				}
				catch
				{
					pocketExpeditionView.Dispose();
					throw;
				}
				view?.Dispose();
				game = idleGame;
				view = pocketExpeditionView;
				saveAccumulator = 0f;
				audio.SetVolume((float)gameState.SoundVolumePercent / 100f);
				audio.SetOverlayActive(active: true, gameState.SoundEnabled);
				if (!overlayInteraction.IsVisible)
				{
					overlayInteraction.ToggleF8();
				}
				ApplyOverlayInteraction(deferGameplayRelease: false);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("저장파일 복구 완료: " + key));
			}
		}

		private void SafeSave(bool snapshot = false)
		{
			if (saveRepository == null || game == null || !game.State.HasStarted || !game.SessionActive)
			{
				return;
			}
			try
			{
				saveRepository.Save(game.State);
				if (snapshot)
				{
					saveRepository.CreateSnapshot(game.State, SaveKind.Auto);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("저장 실패: " + ex));
			}
		}

		private void DisposeRuntime()
		{
			inputFocus?.Dispose();
			view?.Dispose();
			audio?.Dispose();
			assetLoader?.Dispose();
			assetBundle?.Dispose();
			assetBundle = null;
			inputFocus = null;
			view = null;
			assetLoader = null;
			audio = null;
			game = null;
			saveRepository = null;
		}
	}
}
namespace PocketExpedition.Runtime
{
	internal static class AssetLifetime
	{
		public static void Destroy(Object value)
		{
			Object.Destroy(value);
		}
	}
	public sealed class BundleAssetStore : IDisposable
	{
		public const string FileName = "PocketExpedition.assetbundle";

		private readonly AssetBundle bundle;

		private readonly string root;

		private readonly HashSet<string> names;

		private readonly HashSet<AudioClip> audio = new HashSet<AudioClip>();

		private bool disposed;

		public int Count => names.Count - 1;

		public BundleAssetStore(string pluginDirectory, Action<string> log)
		{
			root = Path.GetFullPath(pluginDirectory).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
			string text = Path.Combine(root, "PocketExpedition.assetbundle");
			bundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)bundle == (Object)null)
			{
				throw new InvalidDataException("Cannot load PocketExpedition.assetbundle. Install the matching DLL and assetbundle together.");
			}
			try
			{
				names = new HashSet<string>(bundle.GetAllAssetNames(), StringComparer.Ordinal);
				TextAsset val = bundle.LoadAsset<TextAsset>("__pocket_manifest");
				if ((Object)(object)val == (Object)null || !val.text.StartsWith("PEAB1\n", StringComparison.Ordinal))
				{
					throw new InvalidDataException("Unsupported Pocket Expedition asset bundle");
				}
				Resources.UnloadAsset((Object)(object)val);
				log("AssetBundle loaded: PocketExpedition.assetbundle · " + Count + " assets · Unity " + Application.unityVersion);
			}
			catch
			{
				bundle.Unload(true);
				throw;
			}
		}

		private string Key(string path)
		{
			string text = path;
			if (Path.IsPathRooted(path))
			{
				string fullPath = Path.GetFullPath(path);
				if (!fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase))
				{
					throw new InvalidDataException("Asset path outside plugin: " + path);
				}
				text = fullPath.Substring(root.Length);
			}
			text = text.Replace('\\', '/');
			if (text.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(7);
			}
			if (text.Contains("../") || text.StartsWith("/", StringComparison.Ordinal))
			{
				throw new InvalidDataException("Invalid bundle path");
			}
			return text.ToLowerInvariant();
		}

		public bool Exists(string path)
		{
			if (!disposed)
			{
				return names.Contains(Key(path));
			}
			return false;
		}

		public byte[] ReadBytes(string path)
		{
			if (disposed)
			{
				throw new ObjectDisposedException("BundleAssetStore");
			}
			string text = Key(path);
			TextAsset val = bundle.LoadAsset<TextAsset>(text);
			if ((Object)(object)val == (Object)null)
			{
				throw new FileNotFoundException("Asset missing in bundle", text);
			}
			try
			{
				return val.bytes;
			}
			finally
			{
				Resources.UnloadAsset((Object)(object)val);
			}
		}

		public Stream OpenRead(string path)
		{
			return new MemoryStream(ReadBytes(path), writable: false);
		}

		public AudioClip LoadAudio(string path)
		{
			if (disposed)
			{
				throw new ObjectDisposedException("BundleAssetStore");
			}
			AudioClip val = bundle.LoadAsset<AudioClip>(Key(path));
			if ((Object)(object)val == (Object)null || val.samples <= 0)
			{
				throw new InvalidDataException("Audio missing in bundle: " + path);
			}
			audio.Add(val);
			return val;
		}

		public bool ReleaseAudio(AudioClip clip)
		{
			if ((Object)(object)clip == (Object)null || !audio.Remove(clip))
			{
				return false;
			}
			Resources.UnloadAsset((Object)(object)clip);
			return true;
		}

		public void Dispose()
		{
			if (!disposed)
			{
				disposed = true;
				audio.Clear();
				bundle.Unload(true);
			}
		}
	}
	public sealed class ButtonHoverFeedback : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		public Action? OnHover;

		public float HoverScale = 1.045f;

		private Button button;

		private Vector3 restingScale;

		private bool hovered;

		private float emphasis;

		private void Awake()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			button = ((Component)this).GetComponent<Button>();
			restingScale = ((Component)this).transform.localScale;
		}

		public void OnPointerEnter(PointerEventData eventData)
		{
			if (!hovered && ((Selectable)button).IsInteractable())
			{
				OnHover?.Invoke();
			}
			hovered = true;
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			hovered = false;
		}

		private void Update()
		{
			//IL_0058: 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)
			float num = ((hovered && ((Selectable)button).IsInteractable()) ? 1f : 0f);
			if (!Mathf.Approximately(emphasis, num))
			{
				emphasis = Mathf.MoveTowards(emphasis, num, Time.unscaledDeltaTime / 0.12f);
				((Component)this).transform.localScale = restingScale * Mathf.Lerp(1f, HoverScale, emphasis);
			}
		}

		private void OnDisable()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			hovered = false;
			emphasis = 0f;
			((Component)this).transform.localScale = restingScale;
		}
	}
	internal sealed class CombatDamagePopup
	{
		private readonly List<DamagePopupNumber> numbers = new List<DamagePopupNumber>();

		private readonly Font numericFont;

		private readonly bool incoming;

		public RectTransform Rect { get; }

		public CombatDamagePopup(Transform parent, Font numericFont, bool incoming)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			this.numericFont = numericFont;
			this.incoming = incoming;
			GameObject val = new GameObject(incoming ? "IncomingDamagePopups" : "AttackDamagePopups", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			Rect = (RectTransform)val.transform;
		}

		public void Show(string value, bool critical, bool heavy, float now)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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)
			DamagePopupNumber damagePopupNumber = null;
			foreach (DamagePopupNumber number in numbers)
			{
				if (number.IsAvailable(now))
				{
					damagePopupNumber = number;
					break;
				}
			}
			if (damagePopupNumber == null)
			{
				damagePopupNumber = new DamagePopupNumber((Transform)(object)Rect, numericFont, incoming);
				damagePopupNumber.Rect.anchorMin = Vector2.zero;
				damagePopupNumber.Rect.anchorMax = Vector2.one;
				RectTransform rect = damagePopupNumber.Rect;
				Vector2 offsetMin = (damagePopupNumber.Rect.offsetMax = Vector2.zero);
				rect.offsetMin = offsetMin;
				numbers.Add(damagePopupNumber);
			}
			damagePopupNumber.Show(value, critical, heavy, now);
			((Transform)Rect).SetAsLastSibling();
		}

		public void Tick(float now, bool reducedMotion)
		{
			foreach (DamagePopupNumber number in numbers)
			{
				number.Tick(now, reducedMotion);
			}
		}
	}
	internal sealed class DamagePopupNumber
	{
		private readonly Text number;

		private readonly CanvasGroup group;

		private readonly DamageNumberGradient gradient;

		private readonly Outline outline;

		private readonly Shadow shadow;

		private readonly bool incoming;

		private float startedAt = -10f;

		private bool critical;

		public RectTransform Rect => ((Graphic)number).rectTransform;

		public DamagePopupNumber(Transform parent, Font numericFont, bool incoming)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: 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)
			this.incoming = incoming;
			GameObject val = new GameObject(incoming ? "IncomingDamage" : "AttackDamage", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasGroup),
				typeof(Text)
			});
			val.transform.SetParent(parent, false);
			group = val.GetComponent<CanvasGroup>();
			group.blocksRaycasts = false;
			group.interactable = false;
			number = val.GetComponent<Text>();
			number.font = numericFont;
			number.fontStyle = (FontStyle)0;
			number.alignment = (TextAnchor)4;
			number.horizontalOverflow = (HorizontalWrapMode)1;
			number.verticalOverflow = (VerticalWrapMode)1;
			number.supportRichText = false;
			((Graphic)number).raycastTarget = false;
			gradient = val.AddComponent<DamageNumberGradient>();
			shadow = val.AddComponent<Shadow>();
			shadow.effectColor = new Color(0.12f, 0.025f, 0.018f, 0.95f);
			shadow.effectDistance = new Vector2(4f, -5f);
			outline = val.AddComponent<Outline>();
			((Shadow)outline).effectColor = new Color(0.065f, 0.035f, 0.028f, 1f);
			((Shadow)outline).effectDistance = new Vector2(2f, -2f);
			val.SetActive(false);
		}

		public bool IsAvailable(float now)
		{
			if (((Component)number).gameObject.activeSelf)
			{
				return now - startedAt >= 0.75f;
			}
			return true;
		}

		public void Show(string value, bool isCritical, bool heavy, float now)
		{
			//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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			startedAt = now;
			critical = isCritical && !incoming;
			number.text = value;
			number.fontSize = ((!incoming) ? (critical ? 64 : 40) : (heavy ? 43 : 36));
			gradient.Top = (incoming ? new Color(1f, 0.76f, 0.65f) : (critical ? new Color(1f, 0.88f, 0.12f) : new Color(0.98f, 1f, 1f)));
			gradient.Bottom = (incoming ? new Color(0.98f, 0.1f, 0.14f) : (critical ? new Color(1f, 0.32f, 0.015f) : new Color(0.68f, 0.79f, 0.88f)));
			((Shadow)outline).effectColor = (critical ? new Color(0.23f, 0.065f, 0.005f, 1f) : new Color(0.065f, 0.035f, 0.028f, 1f));
			((Shadow)outline).effectDistance = (critical ? new Vector2(3f, -3f) : (incoming ? new Vector2(2f, -2f) : new Vector2(1.5f, -1.5f)));
			shadow.effectDistance = (critical ? new Vector2(5f, -6f) : new Vector2(4f, -5f));
			((Graphic)number).SetVerticesDirty();
			group.alpha = 1f;
			((Component)number).gameObject.SetActive(true);
			((Transform)Rect).SetAsLastSibling();
		}

		public void Tick(float now, bool reducedMotion)
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			if (((Component)number).gameObject.activeSelf)
			{
				float num = now - startedAt;
				if (num >= 0.75f)
				{
					((Component)number).gameObject.SetActive(false);
					return;
				}
				float num2 = Mathf.Clamp01(num / 0.75f);
				group.alpha = 1f - Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.5f, 0.75f, num));
				float num3 = ((num < 0.075f) ? Mathf.Lerp(0.68f, critical ? 1.32f : 1.18f, num / 0.075f) : Mathf.Lerp(critical ? 1.32f : 1.18f, 1f, Mathf.SmoothStep(0f, 1f, (num - 0.075f) / 0.18f)));
				((Transform)Rect).localScale = Vector3.one * (reducedMotion ? 1f : num3);
				Rect.anchoredPosition = (Vector2)(reducedMotion ? Vector2.zero : new Vector2(0f, 72f * num2));
				((Transform)Rect).localRotation = Quaternion.identity;
			}
		}
	}
	public sealed class DamageNumberGradient : BaseMeshEffect
	{
		public Color Top = Color.white;

		public Color Bottom = Color.white;

		public override void ModifyMesh(VertexHelper mesh)
		{
			//IL_0013: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (((UIBehaviour)this).IsActive() && mesh.currentVertCount != 0)
			{
				UIVertex val = default(UIVertex);
				float num = float.MaxValue;
				float num2 = float.MinValue;
				for (int i = 0; i < mesh.currentVertCount; i++)
				{
					mesh.PopulateUIVertex(ref val, i);
					num = Mathf.Min(num, val.position.y);
					num2 = Mathf.Max(num2, val.position.y);
				}
				for (int j = 0; j < mesh.currentVertCount; j++)
				{
					mesh.PopulateUIVertex(ref val, j);
					Color val2 = Color.Lerp(Bottom, Top, Mathf.InverseLerp(num, num2, val.position.y));
					val2.a *= (float)(int)val.color.a / 255f;
					val.color = Color32.op_Implicit(val2);
					mesh.SetUIVertex(val, j);
				}
			}
		}
	}
	public static class CombatVisualRules
	{
		public static int AttackTier(int level)
		{
			if (level < 150)
			{
				if (level < 75)
				{
					return (level >= 25) ? 1 : 0;
				}
				return 2;
			}
			return 3;
		}

		public static void CooldownBoundary(double remaining, out double x, out double y)
		{
			double num = Math.Max(0.0, Math.Min(1.0, remaining)) * Math.PI * 2.0;
			x = 0.0 - Math.Sin(num);
			y = Math.Cos(num);
			double num2 = 0.5 / Math.Max(Math.Abs(x), Math.Abs(y));
			x *= num2;
			y *= num2;
		}

		public static float PetCenterDistance(float heroSide, float petSide, float pulse)
		{
			return heroSide * 0.5f + petSide * pulse * 0.5f + 12f;
		}
	}
	public sealed class DungeonUiSkin : IDisposable
	{
		private readonly Sprite[] sprites = (Sprite[])(object)new Sprite[5];

		private readonly Texture2D[] textures = (Texture2D[])(object)new Texture2D[5];

		private readonly Sprite[] routeSprites = (Sprite[])(object)new Sprite[3];

		private readonly Sprite[] gaugeSprites = (Sprite[])(object)new Sprite[4];

		public void Gauge(Image image, int kind)
		{
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: 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)
			if ((Object)(object)gaugeSprites[kind] == (Object)null)
			{
				Texture2D val = new Texture2D(128, 32, (TextureFormat)4, false);
				((Object)val).name = "DungeonGauge_" + kind;
				((Texture)val).filterMode = (FilterMode)1;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				byte[] array = RoundedGaugePixels.Create(kind);
				Color32[] array2 = (Color32[])(object)new Color32[4096];
				for (int i = 0; i < 32; i++)
				{
					for (int j = 0; j < 128; j++)
					{
						int num = (i * 128 + j) * 4;
						array2[i * 128 + j] = new Color32(array[num], array[num + 1], array[num + 2], array[num + 3]);
					}
				}
				val.SetPixels32(array2);
				val.Apply(false, true);
				gaugeSprites[kind] = Sprite.Create(val, new Rect(0f, 0f, 128f, 32f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(14f, 14f, 14f, 14f));
			}
			image.sprite = gaugeSprites[kind];
			((Graphic)image).color = Color.white;
			((Graphic)image).raycastTarget = false;
			image.type = (Type)1;
			image.pixelsPerUnitMultiplier = 1.4f;
		}

		public Sprite RouteSprite(int kind)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if ((Object)(object)routeSprites[kind] != (Object)null)
			{
				return routeSprites[kind];
			}
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
			((Object)val).name = "DungeonRoute_" + kind;
			((Texture)val).filterMode = (FilterMode)0;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			byte[] array = DungeonRouteArt.Create(kind);
			Color32[] array2 = (Color32[])(object)new Color32[4096];
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					int num = (i * 64 + j) * 4;
					array2[(63 - i) * 64 + j] = new Color32(array[num], array[num + 1], array[num + 2], array[num + 3]);
				}
			}
			val.SetPixels32(array2);
			val.Apply(false, true);
			return routeSprites[kind] = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f);
		}

		public DungeonUiSkin()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < sprites.Length; i++)
			{
				Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false);
				((Object)val).name = "DungeonSkin_" + i;
				((Texture)val).filterMode = (FilterMode)0;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				byte[] array = DungeonSkinPixels.Create(i);
				Color32[] array2 = (Color32[])(object)new Color32[16384];
				for (int j = 0; j < 128; j++)
				{
					for (int k = 0; k < 128; k++)
					{
						int num = (j * 128 + k) * 4;
						array2[(127 - j) * 128 + k] = new Color32(array[num], array[num + 1], array[num + 2], array[num + 3]);
					}
				}
				val.SetPixels32(array2);
				val.Apply(false, true);
				textures[i] = val;
				sprites[i] = Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(20f, 20f, 20f, 20f));
			}
		}

		public void Panel(Image image, string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (!(((Graphic)image).color.a < 0.1f) && !(name == "ScreenBlocker"))
			{
				int style = ((name.Contains("Gem") || name.Contains("Relic")) ? 2 : 0);
				Apply(image, style);
			}
		}

		public void Button(Image image, string name)
		{
			Apply(image, (name.Contains("Close") || name.Contains("Cancel")) ? 3 : ((!name.Contains("Buy") && !name.Contains("Start")) ? 1 : 4));
		}

		private void Apply(Image image, int style)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			image.sprite = sprites[style];
			image.type = (Type)1;
			image.pixelsPerUnitMultiplier = 1.5f;
			((Graphic)image).color = Color.white;
		}

		public void Dispose()
		{
			Sprite[] array = gaugeSprites;
			foreach (Sprite val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val.texture);
					Object.Destroy((Object)(object)val);
				}
			}
			array = routeSprites;
			foreach (Sprite val2 in array)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2.texture);
					Object.Destroy((Object)(object)val2);
				}
			}
			array = sprites;
			for (int i = 0; i < array.Length; i++)
			{
				Object.Destroy((Object)(object)array[i]);
			}
			Texture2D[] array2 = textures;
			for (int i = 0; i < array2.Length; i++)
			{
				Object.Destroy((Object)(object)array2[i]);
			}
		}
	}
	public sealed class InputFocusController : IDisposable
	{
		private static InputFocusController? active;

		private readonly Harmony harmony = new Harmony("com.pocketexpedition.inputfocus");

		private readonly FieldInfo[] gameplayFields;

		private readonly MethodInfo? refreshHostCursor;

		private CursorLockMode previousLock;

		private bool previousVisible;

		private bool captured;

		private int releaseAfterFrame = -1;

		public Action? BeforeHostInput;

		public bool IsCaptured => captured;

		public InputFocusController()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00ca: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("CharacterInput") ?? throw new InvalidOperationException("PEAK CharacterInput adapter unavailable.");
			gameplayFields = (from f in type.GetFields(BindingFlags.Instance | BindingFlags.Public)
				where (f.FieldType == typeof(bool) && f.Name != "pauseWasPressed" && f.Name != "pushToTalkPressed" && f.Name != "itemSwitchBlocked") || f.Name == "movementInput" || f.Name == "lookInput" || f.Name == "scrollInput"
				select f).ToArray();
			MethodInfo methodInfo = AccessTools.Method(type, "Sample", (Type[])null, (Type[])null) ?? throw new InvalidOperationException("PEAK CharacterInput.Sample unavailable.");
			active = this;
			try
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(InputFocusController), "BeforeSample", (Type[])null), new HarmonyMethod(typeof(InputFocusController), "AfterSample", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				string[] array = new string[2] { "HotbarKeyWasPressed", "HotbarKeyIsPressed" };
				foreach (string text in array)
				{
					harmony.Patch((MethodBase)AccessTools.Method(type, text, (Type[])null, (Type[])null), new HarmonyMethod(typeof(InputFocusController), "BeforeHotbar", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				Type type2 = AccessTools.TypeByName("CursorHandler");
				refreshHostCursor = ((type2 == null) ? null : AccessTools.Method(type2, "Update", (Type[])null, (Type[])null));
				if (refreshHostCursor != null)
				{
					harmony.Patch((MethodBase)refreshHostCursor, (HarmonyMethod)null, new HarmonyMethod(typeof(InputFocusController), "AfterCursor", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		private static void BeforeSample()
		{
			active?.BeforeHostInput?.Invoke();
			active?.Tick();
		}

		private static void AfterSample(object __instance)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (active != null && active.captured)
			{
				FieldInfo[] array = active.gameplayFields;
				foreach (FieldInfo fieldInfo in array)
				{
					fieldInfo.SetValue(__instance, (fieldInfo.FieldType == typeof(Vector2)) ? ((object)Vector2.zero) : ((fieldInfo.FieldType == typeof(float)) ? ((object)0f) : ((object)false)));
				}
			}
		}

		private static bool BeforeHotbar(ref bool __result)
		{
			if (active == null || !active.captured)
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static void AfterCursor()
		{
			InputFocusController? inputFocusController = active;
			if (inputFocusController != null && inputFocusController.captured)
			{
				EnforceCursor();
			}
		}

		public void CaptureForOverlay()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			releaseAfterFrame = -1;
			if (!captured)
			{
				previousLock = Cursor.lockState;
				previousVisible = Cursor.visible;
				captured = true;
			}
			EnforceCursor();
		}

		public void Tick()
		{
			if (releaseAfterFrame >= 0 && Time.frameCount > releaseAfterFrame)
			{
				ReleaseToGame();
			}
			if (captured)
			{
				EnforceCursor();
			}
		}

		public void EnsureOverlayCursor()
		{
			if (captured)
			{
				EnforceCursor();
			}
		}

		public void ReleaseAfterPointerFrame()
		{
			if (captured)
			{
				releaseAfterFrame = Time.frameCount;
			}
		}

		public void ReleaseToGame()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			releaseAfterFrame = -1;
			if (!captured)
			{
				return;
			}
			captured = false;
			Cursor.lockState = previousLock;
			Cursor.visible = previousVisible;
			if (refreshHostCursor?.DeclaringType != null)
			{
				Object val = Object.FindAnyObjectByType(refreshHostCursor.DeclaringType);
				if (val != (Object)null)
				{
					refreshHostCursor.Invoke(val, null);
				}
			}
		}

		public void Dispose()
		{
			ReleaseToGame();
			BeforeHostInput = null;
			harmony.UnpatchSelf();
			if (active == this)
			{
				active = null;
			}
		}

		private static void EnforceCursor()
		{
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
		}
	}
	[DataContract]
	public sealed class ModOptions
	{
		[DataMember]
		public int Music = 100;

		[DataMember]
		public int Sfx = 100;

		[DataMember]
		public int Hits = 100;

		[DataMember]
		public int Ui = 100;

		[DataMember]
		public int LevelUp = 100;

		[DataMember]
		public int BackgroundQuality = 2;

		[DataMember]
		public int Effects = 2;

		[DataMember]
		public int Particles = 2;

		[DataMember]
		public int AntiAliasing;

		[DataMember]
		public bool VSync;

		[DataMember]
		public bool ShowFps = true;

		[DataMember]
		public bool DisplayOptionsInitialized;

		[DataMember]
		public int[] Keys = DefaultKeys();

		private static ModOptions? current;

		public static ModOptions Current => current ?? (current = Load());

		private static string FilePath => Path.Combine(Paths.ConfigPath, "PocketExpedition", "options.json");

		private static int[] DefaultKeys()
		{
			int[] array = new int[13];
			for (int i = 0; i < 4; i++)
			{
				array[i] = 41 + i;
			}
			return array;
		}

		private static ModOptions Load()
		{
			ModOptions modOptions = new ModOptions();
			try
			{
				if (File.Exists(FilePath))
				{
					using FileStream stream = File.OpenRead(FilePath);
					modOptions = (ModOptions)new DataContractJsonSerializer(typeof(ModOptions)).ReadObject(stream);
				}
			}
			catch
			{
			}
			if (modOptions.Keys == null || modOptions.Keys.Length != 13)
			{
				modOptions.Keys = DefaultKeys();
			}
			if (!modOptions.DisplayOptionsInitialized)
			{
				modOptions.AntiAliasing = QualitySettings.antiAliasing;
				modOptions.VSync = QualitySettings.vSyncCount > 0;
				modOptions.ShowFps = true;
				modOptions.DisplayOptionsInitialized = true;
			}
			if (Array.IndexOf(new int[4] { 0, 2, 4, 8 }, modOptions.AntiAliasing) < 0)
			{
				modOptions.AntiAliasing = 0;
			}
			modOptions.Music = Clamp(modOptions.Music);
			modOptions.Sfx = Clamp(modOptions.Sfx);
			modOptions.Hits = Clamp(modOptions.Hits);
			modOptions.Ui = Clamp(modOptions.Ui);
			modOptions.LevelUp = Clamp(modOptions.LevelUp);
			modOptions.BackgroundQuality = Math.Max(0, Math.Min(2, modOptions.BackgroundQuality));
			modOptions.Effects = Math.Max(0, Math.Min(2, modOptions.Effects));
			modOptions.Particles = Math.Max(0, Math.Min(2, modOptions.Particles));
			return modOptions;
		}

		private static int Clamp(int v)
		{
			return Math.Max(0, Math.Min(100, v));
		}

		public void Save()
		{
			Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
			using (FileStream fileStream = new FileStream(FilePath + ".tmp", FileMode.Create, FileAccess.Write, FileShare.None))
			{
				new DataContractJsonSerializer(typeof(ModOptions)).WriteObject(fileStream, this);
				fileStream.Flush(flushToDisk: true);
			}
			if (File.Exists(FilePath))
			{
				File.Replace(FilePath + ".tmp", FilePath, null);
			}
			else
			{
				File.Move(FilePath + ".tmp", FilePath);
			}
		}
	}
	public sealed class PixelAssetLoader : IDisposable
	{
		public const int StructuredFrameCount = 64;

		private const int StructuredGridColumns = 8;

		private const int StructuredGridRows = 8;

		private readonly List<Object> ownedObjects = new List<Object>();

		private readonly SpriteActionCache speciesActions;

		private readonly SpriteActionCache equipmentActions;

		private static readonly string[] EquipmentActionNames = new string[8] { "Idle", "Run", "Attack_A", "Attack_B", "Skill", "Hurt", "Death", "Victory" };

		private static readonly string[] HeroStructuredFiles = new string[8] { "Character_Idle.png", "Character_Run.png", "Character_Attack_A.png", "Character_Attack_B.png", "Character_Skill.png", "Character_Hurt.png", "Character_Death.png", "Character_Victory.png" };

		private static readonly string[] MonsterAStructuredBases = new string[8] { "Monster_A_Slime", "Monster_A_Bat", "Monster_A_Skeleton", "Monster_A_Lava_Golem", "Monster_A_Mushroom", "Monster_A_Ice_Golem", "Monster_A_Wraith", "Monster_A_Mimic" };

		private static readonly string[] MonsterBStructuredBases = new string[8] { "Monster_B_Rat", "Monster_B_Crystal_Beast", "Monster_B_Skull_Shaman", "Monster_B_Water_Wraith", "Monster_B_Magma_Hound", "Monster_B_Frost_Ranger", "Monster_B_Cursed_Tome", "Monster_B_Void_Eye" };

		private static readonly string[] BossStructuredBases = new string[8] { "Boss_Slime_Keeper", "Boss_Bat_Queen", "Boss_Spore_Lord", "Boss_Oblivion_Knight", "Boss_Lava_Titan", "Boss_Frost_King", "Boss_Cursed_Librarian", "Boss_Void_Observer" };

		private static readonly string[] MonsterAStructuredIdleFiles = ActionFiles(MonsterAStructuredBases, "_Idle");

		private static readonly string[] MonsterAStructuredAttackFiles = ActionFiles(MonsterAStructuredBases, "_Attack");

		private static readonly string[] MonsterAStructuredHitFiles = ActionFiles(MonsterAStructuredBases, "_Hurt");

		private static readonly string[] MonsterAStructuredDeathFiles = ActionFiles(MonsterAStructuredBases, "_Death");

		private static readonly string[] MonsterBStructuredIdleFiles = ActionFiles(MonsterBStructuredBases, "_Idle");

		private static readonly string[] MonsterBStructuredAttackFiles = ActionFiles(MonsterBStructuredBases, "_Attack");

		private static readonly string[] MonsterBStructuredHitFiles = ActionFiles(MonsterBStructuredBases, "_Hurt");

		private static readonly string[] MonsterBStructuredDeathFiles = ActionFiles(MonsterBStructuredBases, "_Death");

		private static readonly string[] BossStructuredIdleFiles = ActionFiles(BossStructuredBases, "_Idle");

		private static readonly string[] BossStructuredAttackFiles = ActionFiles(BossStructuredBases, "_Attack");

		private static readonly string[] BossStructuredHitFiles = ActionFiles(BossStructuredBases, "_Hurt");

		private static readonly string[] BossStructuredDeathFiles = ActionFiles(BossStructuredBases, "_Death");

		private static readonly string[] HeroStripFiles = new string[8] { "hero_idle.png", "hero_run.png", "hero_attack_a.png", "hero_attack_b.png", "hero_skill.png", "hero_hurt.png", "hero_death.png", "hero_victory.png" };

		private static readonly string[] MonsterAStripFiles = new string[8] { "monster_a_slime.png", "monster_a_bat.png", "monster_a_skeleton.png", "monster_a_lava_golem.png", "monster_a_mushroom.png", "monster_a_ice_golem.png", "monster_a_wraith.png", "monster_a_mimic.png" };

		private static readonly string[] MonsterBStripFiles = new string[8] { "monster_b_rat.png", "monster_b_crystal_beast.png", "monster_b_skull_shaman.png", "monster_b_water_wraith.png", "monster_b_magma_hound.png", "monster_b_frost_ranger.png", "monster_b_cursed_tome.png", "monster_b_void_eye.png" };

		private static readonly string[] BossStripFiles = new string[8] { "boss_slime_keeper.png", "boss_bat_queen.png", "boss_spore_lord.png", "boss_oblivion_knight.png", "boss_lava_titan.png", "boss_frost_king.png", "boss_cursed_librarian.png", "boss_void_observer.png" };

		private readonly Sprite?[] menuSymbols = (Sprite?[])(object)new Sprite[2];

		public BundleAssetStore Bundle { get; }

		public Sprite[] HeroFrames { get; private set; } = Array.Empty<Sprite>();

		public Sprite? HeroFrontFace { get; private set; }

		public Sprite? HeroFrontBody { get; private set; }

		public Sprite?[] BasicAttackEffects { get; } = (Sprite?[])(object)new Sprite[3];

		public Sprite[] MonsterFramesA { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] MonsterFramesB { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] MonsterAttackFramesA { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] MonsterAttackFramesB { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] MonsterHitFramesA { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] MonsterHitFramesB { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] MonsterDeathFramesA { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] MonsterDeathFramesB { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] BossFrames { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] BossAttackFrames { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] BossHitFrames { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] BossDeathFrames { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] EffectFrames { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] CombatEffectFrames { get; private set; } = Array.Empty<Sprite>();

		public Sprite? LevelUpEffect { get; private set; }

		public Sprite? QuestCompleteEffect { get; private set; }

		public Sprite?[] SkillEffects { get; } = (Sprite?[])(object)new Sprite[4];

		public Sprite[] UiIcons { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] EquipmentIcons { get; private set; } = Array.Empty<Sprite>();

		public Sprite?[] EquipmentVisuals { get; } = (Sprite?[])(object)new Sprite[18];

		public Sprite[] Backgrounds { get; private set; } = Array.Empty<Sprite>();

		public Sprite[] TitleBackground { get; private set; } = Array.Empty<Sprite>();

		public Sprite?[] WindowGlyphs { get; } = (Sprite?[])(object)new Sprite[4];

		public Texture2D?[] ResizeCursors { get; } = (Texture2D?[])(object)new Texture2D[2];

		public bool IsComplete { get; private set; }

		public string AssetDirectory { get; private set; } = "";

		public PixelAssetLoader(BundleAssetStore bundle)
		{
			Bundle = bundle;
			speciesActions = new SpriteActionCache(6, bundle.OpenRead);
			equipmentActions = new SpriteActionCache(32, bundle.OpenRead);
		}

		public Sprite EquipmentFrame(int itemId, int action, int frame)
		{
			return equipmentActions.Get(Path.Combine(AssetDirectory, "EquipmentVisuals", "Actions", itemId + "_" + EquipmentActionNames[action] + ".png"))[frame];
		}

		public Sprite ArmedHeroFrame(int action, int frame)
		{
			return equipmentActions.Get(Path.Combine(AssetDirectory, "EquipmentVisuals", "Actions", "hero_" + EquipmentActionNames[action] + ".png"))[frame];
		}

		public Sprite[] SpeciesFrames(int species, string action)
		{
			return speciesActions.Get(Path.Combine(AssetDirectory, "NewSpecies", CombatSoundCatalog.SpeciesIds[species] + "_" + action + ".png"));
		}

		public Sprite[] GuardianFrames(string action)
		{
			return speciesActions.Get(Path.Combine(AssetDirectory, "Guardian", "Guardian_" + action + ".png"));
		}

		private static string[] ActionFiles(string[] bases, string suffix)
		{
			string[] array = new string[bases.Length];
			for (int i = 0; i < bases.Length; i++)
			{
				array[i] = bases[i] + suffix + ".png";
			}
			return array;
		}

		public void Load(string pluginDirectory, Action<string> log)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_046d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0513: Unknown result type (might be due to invalid IL or missing references)
			//IL_0554: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0693: Unknown result type (might be due to invalid IL or missing references)
			//IL_074b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0752: Expected O, but got Unknown
			//IL_0817: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0947: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a34: Unknown result type (might be due to invalid IL or missing references)
			string assetDirectory = Path.Combine(pluginDirectory, "Assets");
			AssetDirectory = assetDirectory;
			TitleBackground = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "Menu/title-dungeon-expedition.png"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
			if (TitleBackground.Length != 0)
			{
				((Texture)TitleBackground[0].texture).filterMode = (FilterMode)1;
			}
			HeroFrames = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\characters", HeroStructuredFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => LoadSeparatedRows(pluginDirectory, assetDirectory, "characters_v2", HeroStripFiles, ResolvePath(pluginDirectory, assetDirectory, "hero_master_8x8.png"), 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0.08f), log, 24, 0));
			MonsterFramesA = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\monsters", MonsterAStructuredIdleFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => LoadSeparatedRows(pluginDirectory, assetDirectory, "monsters_v2", MonsterAStripFiles, ResolvePath(pluginDirectory, assetDirectory, "monsters_a_8x8.png"), 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0.08f), log, 0, 0));
			MonsterAttackFramesA = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\monsters", MonsterAStructuredAttackFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => MonsterFramesA);
			MonsterHitFramesA = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\monsters", MonsterAStructuredHitFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => MonsterFramesA);
			MonsterDeathFramesA = Array.Empty<Sprite>();
			MonsterFramesB = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\monsters", MonsterBStructuredIdleFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => LoadSeparatedRows(pluginDirectory, assetDirectory, "monsters_v2", MonsterBStripFiles, ResolvePath(pluginDirectory, assetDirectory, "monsters_b_8x8.png"), 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0.08f), log, 0, 0));
			MonsterAttackFramesB = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\monsters", MonsterBStructuredAttackFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => MonsterFramesB);
			MonsterHitFramesB = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\monsters", MonsterBStructuredHitFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => MonsterFramesB);
			MonsterDeathFramesB = Array.Empty<Sprite>();
			BossFrames = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\bosses", BossStructuredIdleFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => LoadSeparatedRows(pluginDirectory, assetDirectory, "bosses_v2", BossStripFiles, ResolvePath(pluginDirectory, assetDirectory, "bosses_8x8.png"), 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0.08f), log, 0, 0));
			BossAttackFrames = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\bosses", BossStructuredAttackFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => BossFrames);
			BossHitFrames = LoadStructuredRows(pluginDirectory, assetDirectory, "structured_v5\\bosses", BossStructuredHitFiles, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0f), log, () => BossFrames);
			BossDeathFrames = Array.Empty<Sprite>();
			EffectFrames = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "effects_8x8.png"), 8, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0.5f), log);
			CombatEffectFrames = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "structured_v5\\effects\\Combat_Slash_64.png"), 8, 8, cleanGeneratedBackground: false, new Vector2(0.5f, 0f), log, 0f, 0, 0, "Combat_Slash_64", 0, 8);
			UiIcons = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "ui_icons_8x8.png"), 8, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0.5f), log);
			Sprite[] array = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "SkillEffects/level-up.png"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
			LevelUpEffect = ((array.Length == 1) ? array[0] : null);
			Sprite[] array2 = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "SkillEffects/quest-complete.png"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
			QuestCompleteEffect = ((array2.Length == 1) ? array2[0] : null);
			Sprite[] array3 = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "Portraits/hero-front-face.png"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
			Sprite[] array4 = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "Portraits/hero-front-body.png"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
			HeroFrontFace = ((array3.Length == 1) ? array3[0] : null);
			HeroFrontBody = ((array4.Length == 1) ? array4[0] : null);
			string[] array5 = new string[3] { "slash-25", "slash-75", "slash-150" };
			for (int num = 0; num < array5.Length; num++)
			{
				Sprite[] array6 = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "AttackEffects/" + array5[num] + ".png"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
				BasicAttackEffects[num] = ((array6.Length == 1) ? array6[0] : null);
			}
			string[] array7 = new string[4] { "minimize", "maximize", "restore", "close" };
			for (int num2 = 0; num2 < array7.Length; num2++)
			{
				Sprite[] array8 = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "WindowChrome/" + array7[num2] + ".png"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
				WindowGlyphs[num2] = ((array8.Length == 1) ? array8[0] : null);
			}
			string[] array9 = new string[2] { "resize-nwse", "resize-nesw" };
			for (int num3 = 0; num3 < array9.Length; num3++)
			{
				string text = ResolvePath(pluginDirectory, assetDirectory, "WindowChrome/" + array9[num3] + ".png");
				if (!Bundle.Exists(text))
				{
					log("Resize cursor missing: " + text);
					continue;
				}
				Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false);
				ownedObjects.Add((Object)(object)val);
				if (ImageConversion.LoadImage(val, Bundle.ReadBytes(text), false) && ((Texture)val).width == 32 && ((Texture)val).height == 32)
				{
					((Texture)val).filterMode = (FilterMode)0;
					((Texture)val).wrapMode = (TextureWrapMode)1;
					ResizeCursors[num3] = val;
				}
			}
			string[] array10 = new string[4] { "rift-cut.png", "rally.png", "stone-ward.png", "judgment.png" };
			for (int num4 = 0; num4 < array10.Length; num4++)
			{
				Sprite[] array11 = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "SkillEffects/" + array10[num4]), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
				SkillEffects[num4] = ((array11.Length == 1) ? array11[0] : null);
				if ((Object)(object)SkillEffects[num4] == (Object)null)
				{
					log("스킬 이펙트 누락: " + array10[num4]);
				}
			}
			EquipmentIcons = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "equipment_8x8.png"), 8, 8, cleanGeneratedBackground: true, new Vector2(0.5f, 0.5f), log, 0f, 0, 0, null, 0, -1, trimAlpha: true);
			for (int num5 = 0; num5 < 18; num5++)
			{
				EquipmentDefinition equipmentDefinition = EquipmentCatalog.Get(num5);
				Sprite[] array12 = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "EquipmentVisuals/" + (int)equipmentDefinition.Slot + "_" + equipmentDefinition.Tier + ".png"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log);
				EquipmentVisuals[num5] = ((array12.Length == 1) ? array12[0] : null);
			}
			Backgrounds = LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "dungeons_4x2.png"), 4, 2, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log, 1.65f);
			List<Sprite> list = new List<Sprite>(Backgrounds);
			string[] array13 = new string[2] { "forge", "crypt" };
			foreach (string text2 in array13)
			{
				list.AddRange(LoadGrid(ResolvePath(pluginDirectory, assetDirectory, "ThemeBackgrounds/" + text2 + ".jpg"), 1, 1, cleanGeneratedBackground: false, new Vector2(0.5f, 0.5f), log));
			}
			Backgrounds = list.ToArray();
			IsComplete = (Object)(object)LevelUpEffect != (Object)null && HeroFrames.Length == 64 * HeroStructuredFiles.Length && MonsterFramesA.Length == 64 * MonsterAStructuredBases.Length && MonsterFramesB.Length == 64 * MonsterBStructuredBases.Length && MonsterAttackFramesA.Length == 64 * MonsterAStructuredBases.Length && MonsterAttackFramesB.Length == 64 * MonsterBStructuredBases.Length && MonsterHitFramesA.Length == 64 * MonsterAStructuredBases.Length && MonsterHitFramesB.Length == 64 * MonsterBStructuredBases.Length && BossFrames.Length == 64 * BossStructuredBases.Length && BossAttackFrames.Length == 64 * BossStructuredBases.Length && BossHitFrames.Length == 64 * BossStructuredBases.Length && EffectFrames.Length == 64 && CombatEffectFrames.Length == 64 && Array.TrueForAll(SkillEffects, (Sprite s) => (Object)(object)s != (Object)null) && UiIcons.Length == 64 && EquipmentIcons.Length == 64 && Backgrounds.Length == 10;
			log(IsComplete ? "분리 스프라이트 시트와 던전 테마 10개 로드 완료" : "일부 에셋이 누락되어 폴백 표시를 사용함");
		}

		public Sprite? Icon(int row, int column)
		{
			return At(UiIcons, row, column);
		}

		public Sprite? Equipment(int row, int column)
		{
			return At(EquipmentIcons, row, column);
		}

		public Sprite? EquipmentVisual(int id)
		{
			if (id < 0 || id >= EquipmentVisuals.Length)
			{
				return null;
			}
			return EquipmentVisuals[id];
		}

		public Sprite? Effect(int row, int column)
		{
			return At(EffectFrames, row, column);
		}

		private static Sprite? At(Sprite[] frames, int row, int column)
		{
			int num = Math.Max(0, row) * 8 + Math.Max(0, column);
			if (num >= frames.Length)
			{
				return null;
			}
			return frames[num];
		}

		private string ResolvePath(string pluginDirectory, string assetDirectory, string fileName)
		{
			string text = Path.Combine(assetDirectory, fileName);
			if (!Bundle.Exists(text))
			{
				return Path.Combine(pluginDirectory, fileName);
			}
			return text;
		}

		private string ResolveSeparatedPath(string pluginDirectory, string assetDirectory, string folder, string fileName)
		{
			string text = Path.Combine(assetDirectory, folder, fileName);
			if (Bundle.Exists(text))
			{
				return text;
			}
			string text2 = Path.Combine(pluginDirectory, folder, fileName);
			if (!Bundle.Exists(text2))
			{
				return text;
			}
			return text2;
		}

		private static Sprite[] FirstRow(Sprite[] frames, int columns)
		{
			if (frames == null || frames.Length < columns)
			{
				return Array.Empty<Sprite>();
			}
			Sprite[] array = (Sprite[])(object)new Sprite[columns];
			Array.Copy(frames, 0, array, 0, columns);
			return array;
		}

		private Sprite[] LoadStructuredRows(string pluginDirectory, string assetDirectory, string folder, string[] rowFiles, int columns, bool cleanGeneratedBackground, Vector2 pivot, Action<string> log, Func<Sprite[]> fallbackLoader)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Sprite[] array = (Sprite[])(object)new Sprite[64 * rowFiles.Length];
			bool[] array2 = new bool[rowFiles.Length];
			for (int i = 0; i < rowFiles.Length; i++)
			{
				string path = ResolveSeparatedPath(pluginDirectory, assetDirectory, folder, rowFiles[i]);
				if (Bundle.Exists(path))
				{
					Sprite[] array3 = LoadGrid(path, 8, 8, cleanGeneratedBackground: false, pivot, log, 0f, 0, 0, Path.GetFileNameWithoutExtension(rowFiles[i]), 0, 8);
					if (array3.Length >= 64)
					{
						Array.Copy(array3, 0, array, i * 64, 64);
						array2[i] = true;
					}
				}
			}
			bool flag = false;
			for (int j = 0; j < array2.Length; j++)
			{
				if (!array2[j])
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return array;
			}
			Sprite[] array4 = fallbackLoader();
			if (array4.Length == 0)
			{
				return array;
			}
			for (int k = 0; k < array2.Length; k++)
			{
				if (!array2[k])
				{
					int num = k * columns;
					int num2 = k * 64;
					for (int l = 0; l < 64; l++)
					{
						array[num2 + l] = array4[(num + l) % array4.Length];
					}
				}
			}
			return array;
		}

		private Sprite[] LoadSeparatedRows(string pluginDirectory, string assetDirectory, string folder, string[] rowFiles, string combinedPath, int columns, bool cleanGeneratedBackground, Vector2 pivot, Action<string> log, int edgeCropTop, int edgeCropBottom)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			Sprite[] array = (Sprite[])(object)new Sprite[columns * rowFiles.Length];
			bool[] array2 = new bool[rowFiles.Length];
			for (int i = 0; i < rowFiles.Length; i++)
			{
				string path = ResolveSeparatedPath(pluginDirectory, assetDirectory, folder, rowFiles[i]);
				if (Bundle.Exists(path))
				{
					Sprite[] array3 = LoadGrid(path, columns, 1, cleanGeneratedBackground, pivot, log, 0f, (i != 0) ? edgeCropTop : 0, (i != rowFiles.Length - 1 && i != 0) ? edgeCropBottom : 0);
					if (array3.Length == columns)
					{
						Array.Copy(array3, 0, array, i * columns, columns);
						array2[i] = true;
					}
				}
			}
			bool flag = false;
			for (int j = 0; j < array2.Length; j++)
			{
				if (!array2[j])
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return array;
			}
			Sprite[] array4 = LoadGrid(combinedPath, columns, rowFiles.Length, cleanGeneratedBackground, pivot, log);
			if (array4.Length != array.Length)
			{
				return array;
			}
			for (int k = 0; k < array2.Length; k++)
			{
				if (!array2[k])
				{
					Array.Copy(array4, k * columns, array, k * columns, columns);
				}
			}
			return array;
		}

		public void Dispose()
		{
			speciesActions.Dispose();
			equipmentActions.Dispose();
			for (int num = ownedObjects.Count - 1; num >= 0; num--)
			{
				if (ownedObjects[num] != (Object)null)
				{
					AssetLifetime.Destroy(ownedObjects[num]);
				}
			}
			ownedObjects.Clear();
		}

		private Sprite[] LoadGrid(string path, int columns, int rows, bool cleanGeneratedBackground, Vector2 pivot, Action<string> log, float cropAspect = 0f, int edgeCropTop = 0, int edgeCropBottom = 0, string? spriteNamePrefix = null, int firstRow = 0, int rowCount = -1, bool trimAlpha = false)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Expected O, but got Unknown
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			if (!Bundle.Exists(path))
			{
				log("에셋 누락: " + path);
				return Array.Empty<Sprite>();
			}
			try
			{
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				((Object)val).name = Path.GetFileNameWithoutExtension(path);
				if (!ImageConversion.LoadImage(val, Bundle.ReadBytes(path), false))
				{
					AssetLifetime.Destroy((Object)(object)val);
					return Array.Empty<Sprite>();
				}
				if (!string.IsNullOrEmpty(spriteNamePrefix) && (((Texture)val).width != 2048 || ((Texture)val).height != 2048 || columns != 8 || rows != 8))
				{
					log("구조형 시트 규격 오류: " + Path.GetFileName(path) + " · 2048x2048 / 8x8 필요");
					AssetLifetime.Destroy((Object)(object)val);
					return Array.Empty<Sprite>();
				}
				((Texture)val).filterMode = (FilterMode)0;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				if (cleanGeneratedBackground)
				{
					RemoveGeneratedBackdrop(val);
				}
				int num = Math.Max(0, Math.Min(rows - 1, firstRow));
				int num2 = ((rowCount < 0) ? rows : Math.Max(1, Math.Min(rows - num, rowCount)));
				Sprite[] array = (Sprite[])(object)new Sprite[columns * num2];
				Rect val3 = default(Rect);
				for (int i = 0; i < num2; i++)
				{
					int num3 = num + i;
					int num4 = Mathf.RoundToInt((float)(((Texture)val).height * (rows - num3)) / (float)rows);
					int num5 = Mathf.RoundToInt((float)(((Texture)val).height * (rows - num3 - 1)) / (float)rows);
					for (int j = 0; j < columns; j++)
					{
						int num6 = Mathf.RoundToInt((float)(((Texture)val).width * j) / (float)columns);
						int num7 = Mathf.RoundToInt((float)(((Texture)val).width * (j + 1)) / (float)columns);
						int num8 = Math.Max(1, num7 - num6);
						int num9 = Math.Max(1, num4 - num5);
						if (cropAspect > 0f)
						{
							int val2 = Math.Max(1, Mathf.RoundToInt((float)num8 / cropAspect));
							num9 = Math.Min(num9, val2);
						}
						int num10 = (cleanGeneratedBackground ? 2 : 0);
						int num11 = Math.Min(Math.Max(0, edgeCropTop), Math.Max(0, num9 - num10 * 2 - 1));
						int num12 = Math.Min(Math.Max(0, edgeCropBottom), Math.Max(0, num9 - num10 * 2 - num11 - 1));
						((Rect)(ref val3))..ctor((float)(num6 + num10), (float)(num5 + num10 + num12), (float)Math.Max(1, num8 - num10 * 2), (float)Math.Max(1, num9 - num10 * 2 - num11 - num12));
						if (trimAlpha)
						{
							int num13 = (int)((Rect)(ref val3)).width;
							int num14 = (int)((Rect)(ref val3)).height;
							int num15 = num13;
							int num16 = num14;
							int num17 = -1;
							int num18 = -1;
							Color[] pixels = val.GetPixels((int)((Rect)(ref val3)).x, (int)((Rect)(ref val3)).y, num13, num14);
							for (int k = 0; k < num14; k++)
							{
								for (int l = 0; l < num13; l++)
								{
									if (pixels[k * num13 + l].a > 0.1f)
									{
										num15 = Math.Min(num15, l);
										num16 = Math.Min(num16, k);
										num17 = Math.Max(num17, l);
										num18 = Math.Max(num18, k);
									}
								}
							}
							if (num17 >= num15)
							{
								((Rect)(ref val3))..ctor(((Rect)(ref val3)).x + (float)num15, ((Rect)(ref val3)).y + (float)num16, (float)(num17 - num15 + 1), (float)(num18 - num16 + 1));
							}
						}
						int num19 = Math.Max(1, Mathf.RoundToInt(((Rect)(ref val3)).width));
						int num20 = Math.Max(1, Mathf.RoundToInt(((Rect)(ref val3)).height));
						Texture2D val4 = new Texture2D(num19, num20, (TextureFormat)4, false);
						string text = (string.IsNullOrEmpty(spriteNamePrefix) ? ((Object)val).name : spriteNamePrefix);
						((Object)val4).name = text + "_cell_" + num3 + "_" + j;
						((Texture)val4).filterMode = (FilterMode)0;
						((Texture)val4).wrapMode = (TextureWrapMode)1;
						val4.SetPixels(val.GetPixels(Mathf.RoundToInt(((Rect)(ref val3)).x), Mathf.RoundToInt(((Rect)(ref val3)).y), num19, num20));
						val4.Apply(false, true);
						ownedObjects.Add((Object)(object)val4);
						Sprite val5 = Sprite.Create(val4, new Rect(0f, 0f, (float)num19, (float)num20), pivot, 100f, 0u, (SpriteMeshType)0);
						if (!string.IsNullOrEmpty(spriteNamePrefix))
						{
							((Object)val5).name = spriteNamePrefix + "_" + (num3 * columns + j).ToString("00");
						}
						else
						{
							((Object)val5).name = text + "_r" + num3.ToString("00") + "_c" + j.ToString("00");
						}
						array[i * columns + j] = val5;
						ownedObjects.Add((Object)(object)val5);
					}
				}
				AssetLifetime.Destroy((Object)(object)val);
				return array;
			}
			catch (Exception ex)
			{
				log("에셋 로드 실패(" + Path.GetFileName(path) + "): " + ex.Message);
				return Array.Empty<Sprite>();
			}
		}

		private static void RemoveGeneratedBackdrop(Texture2D texture)
		{
			Color32[] pixels = texture.GetPixels32();
			if (pixels.Length == 0)
			{
				return;
			}
			int width = ((Texture)texture).width;
			int height = ((Texture)texture).height;
			int num = 0;
			if (pixels[0].a < 32)
			{
				num++;
			}
			if (pixels[width - 1].a < 32)
			{
				num++;
			}
			if (pixels[(height - 1) * width].a < 32)
			{
				num++;
			}
			if (pixels[^1].a < 32)
			{
				num++;
			}
			if (num >= 2)
			{
				return;
			}
			bool[] visited = new bool[pixels.Length];
			Queue<int> queue = new Queue<int>();
			for (int i = 0; i < width; i++)
			{
				TryEnqueue(i, pixels, visited, queue);
				TryEnqueue((height - 1) * width + i, pixels, visited, queue);
			}
			for (int j = 0; j < height; j++)
			{
				TryEnqueue(j * width, pixels, visited, queue);
				TryEnqueue(j * width + width - 1, pixels, visited, queue);
			}
			while (queue.Count > 0)
			{
				int num2 = queue.Dequeue();
				pixels[num2].a = 0;
				int num3 = num2 % width;
				int num4 = num2 / width;
				if (num3 > 0)
				{
					TryEnqueue(num2 - 1, pixels, visited, queue);
				}
				if (num3 + 1 < width)
				{
					TryEnqueue(num2 + 1, pixels, visited, queue);
				}
				if (num4 > 0)
				{
					TryEnqueue(num2 - width, pixels, visited, queue);
				}
				if (num4 + 1 < height)
				{
					TryEnqueue(num2 + width, pixels, visited, queue);
				}
			}
			texture.SetPixels32(pixels);
			texture.Apply(false, false);
		}

		private static void TryEnqueue(int index, Color32[] pixels, bool[] visited, Queue<int> queue)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!visited[index])
			{
				visited[index] = true;
				Color32 val = pixels[index];
				byte num = Math.Max(val.r, Math.Max(val.g, val.b));
				byte b = Math.Min(val.r, Math.Min(val.g, val.b));
				bool flag = num - b < 24;
				bool flag2 = num < 42;
				bool flag3 = flag && b > 82;
				if (val.a < 20 || flag2 || flag3)
				{
					queue.Enqueue(index);
				}
			}
		}

		public Sprite MenuSymbol(bool ranking)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Expected O, but got Unknown
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			int num = (ranking ? 1 : 0);
			if ((Object)(object)menuSymbols[num] != (Object)null)
			{
				return menuSymbols[num];
			}
			Color[] pixels = (Color[])(object)new Color[9216];
			Color val = default(Color);
			((Color)(ref val))..ctor(0.12f, 0.15f, 0.21f);
			Color color = default(Color);
			((Color)(ref color))..ctor(1f, 0.76f, 0.22f);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.7f, 0.83f, 0.94f);
			if (ranking)
			{
				Box(40, 15, 14, 51, val);
				Box(44, 18, 6, 46, new Color(0.63f, 0.34f, 0.15f));
				Box(20, 54, 57, 23, val);
				Box(24, 58, 49, 15, val2);
				Box(26, 68, 45, 4, Color.white);
				Box(69, 13, 7, 24, color);
				Box(62, 31, 21, 5, color);
				Box(65, 36, 15, 5, color);
				Box(69, 41, 7, 5, color);
			}
			else
			{
				for (int i = 0; i < 96; i++)
				{
					for (int j = 0; j < 96; j++)
					{
						float num2 = (float)j - 48f;
						float num3 = (float)i - 48f;
						float num4 = (num2 - num3) * 0.70710677f;
						float num5 = (num2 + num3) * 0.70710677f;
						Color val3 = Color.clear;
						if (Mathf.Abs(num4) <= 8f && num5 >= -39f && num5 <= 19f)
						{
							val3 = val;
						}
						if (Mathf.Abs(num4) <= 5f && num5 >= -35f && num5 <= 17f)
						{
							((Color)(ref val3))..ctor(0.58f, 0.29f, 0.12f);
						}
						if (num4 >= -4f && num4 <= -1f && num5 >= -34f && num5 <= 15f)
						{
							((Color)(ref val3))..ctor(0.87f, 0.56f, 0.25f);
						}
						if (Mathf.Abs(num4) <= 25f && num5 >= 9f && num5 <= 32f)
						{
							val3 = val;
						}
						if (Mathf.Abs(num4) <= 21f && num5 >= 13f && num5 <= 28f)
						{
							val3 = val2;
						}
						if (Mathf.Abs(num4) <= 20f && num5 >= 24f && num5 <= 28f)
						{
							val3 = Color.white;
						}
						if (num4 >= 16f && num4 <= 21f && num5 >= 13f && num5 <= 24f)
						{
							((Color)(ref val3))..ctor(0.37f, 0.5f, 0.65f);
						}
						pixels[i * 96 + j] = val3;
					}
				}
			}
			Texture2D val4 = new Texture2D(96, 96, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				wrapMode = (TextureWrapMode)1
			};
			val4.SetPixels(pixels);
			val4.Apply(false, true);
			Sprite val5 = Sprite.Create(val4, new Rect(0f, 0f, 96f, 96f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
			ownedObjects.Add((Object)(object)val4);
			ownedObjects.Add((Object)(object)val5);
			menuSymbols[num] = val5;
			return val5;
			void Box(int x, int y, int w, int h, Color val6)
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				for (int k = Mathf.Max(0, y); k < Mathf.Min(96, y + h); k++)
				{
					for (int l = Mathf.Max(0, x); l < Mathf.Min(96, x + w); l++)
					{
						pixels[k * 96 + l] = val6;
					}
				}
			}
		}
	}
	public sealed class PocketAudio : IDisposable
	{
		private sealed class CombatVoice
		{
			public AudioSource Source;

			public AudioClip? Pending;

			public float Started;

			public float ReplaceAt;

			public float Gain;

			public float PendingGain;

			public float DuckUntil;

			public bool Important;

			public bool PendingImportant;

			public bool Species;

			public bool PendingSpecies;
		}

		private enum Wave
		{
			Sine,
			Square,
			Triangle
		}

		private const int SampleRate = 22050;

		public const int MusicTrackCount = 9;

		public static readonly string[] MusicTrackNamesKorean = MusicCatalog.KoreanNames;

		public static readonly string[] MusicTrackNamesEnglish = MusicCatalog.EnglishNames;

		private readonly GameObject root;

		private readonly AudioSource music;

		private readonly AudioSource effects;

		private readonly Dictionary<string, AudioClip> clips = new Dictionary<string, AudioClip>();

		private readonly Action<string> log;

		private const float BaseMusicVolume = 0.58f;

		private const float BaseEffectsVolume = 0.82f;

		private const float EffectGainBoost = 2f;

		private bool disposed;

		private int musicTrackIndex = -1;

		private readonly MusicShuffle playlist = new MusicShuffle(8);

		private bool musicStarted;

		private bool musicPaused;

		private bool expeditionActive;

		private string audioProfile = "";

		private float retryMusicAt;

		private readonly string musicDirectory;

		private readonly BundleAssetStore bundle;

		private readonly CombatVoice[] combatVoices = new CombatVoice[6];

		private float masterVolume = 1f;

		private int hurtIndex;

		private int lastImpact = -1;

		private float lastHurtAt = -100f;

		private bool overlayActive;

		private bool soundEnabled;

		private float lastHoverSound = -100f;

		private float lastLevelUpSound = -10f;

		public bool IsMusicLoading
		{
			get
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Invalid comparison between Unknown and I4
				if ((Object)(object)music.clip != (Object)null)
				{
					return (int)music.clip.loadState == 1;
				}
				return false;
			}
		}

		public bool MusicLoadFailed { get; private set; }

		public int MusicTrackIndex => musicTrackIndex;

		public PocketAudio(string pluginDirectory, BundleAssetStore bundle, Action<string> log)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			this.log = log;
			this.bundle = bundle;
			musicDirectory = Path.Combine(pluginDirectory, "Assets", "Music");
			root = new GameObject("PocketExpeditionAudio");
			Object.DontDestroyOnLoad((Object)(object)root);
			music = root.AddComponent<AudioSource>();
			effects = root.AddComponent<AudioSource>();
			for (int i = 0; i < combatVoices.Length; i++)
			{
				AudioSource val = root.AddComponent<AudioSource>();
				val.playOnAwake = false;
				val.ignoreListenerPause = true;
				val.spatialBlend = 0f;
				combatVoices[i] = new CombatVoice
				{
					Source = val
				};
			}
			music.loop = false;
			music.playOnAwake = false;
			music.ignoreListenerPause = true;
			effects.ignoreListenerPause = true;
			music.spatialBlend = 0f;
			effects.spatialBlend = 0f;
			music.priority = 0;
			effects.priority = 0;
			music.volume = 0.58f;
			effects.volume = 0.82f;
			clips["click"] = MakeTone("ui_click", 0.075f, 620f, 920f, Wave.Square, 0.36f);
			LoadCombatEffects(pluginDirectory, new string[4] { "player_normal.wav", "player_critical.wav", "player_hurt_01.wav", "player_hurt_02.wav" });
			LoadCombatEffects(pluginDirectory, CombatSoundCatalog.SpeciesAttacks);
			clips["death"] = MakeTone("enemy_down", 0.28f, 260f, 55f, Wave.Triangle, 0.48f);
			clips["portal"] = MakeTone("portal", 0.42f, 260f, 760f, Wave.Sine, 0.4f);
			LoadCombatEffects(pluginDirectory, new string[1] { "level_up.wav" });
			LoadCombatEffects(pluginDirectory, new string[1] { "quest_complete.ogg" });
			clips["skill1"] = MakeNoiseSweep("skill_rift_cut", 0.12f, 0.28f);
			clips["skill2"] = MakeTone("skill_rally", 0.28f, 180f, 480f, Wave.Triangle, 0.3f);
			clips["skill3"] = MakeTone("skill_stone_ward", 0.32f, 620f, 260f, Wave.Triangle, 0.28f);
			clips["skill4"] = MakeNoiseSweep("skill_judgment", 0.2f, 0.34f);
			SetMusicTrack(8);
			log("오디오 준비 완료 · " + AudioSettings.outputSampleRate + "Hz · 던전 배경음 " + 9 + "종 · Listener 일시정지 무시");
		}

		public void SetOverlayActive(bool active, bool enabled)
		{
			if (disposed)
			{
				return;
			}
			overlayActive = active;
			soundEnabled = enabled;
			effects.mute = !active || !enabled;
			CombatVoice[] array = combatVoices;
			foreach (CombatVoice combatVoice in array)
			{
				combatVoice.Source.mute = effects.mute;
				if (effects.mute)
				{
					combatVoice.Source.Stop();
					combatVoice.Pending = null;
				}
			}
			music.mute = !active || !enabled;
			if (active && enabled && (Object)(object)music.clip != (Object)null)
			{
				if (musicPaused)
				{
					music.UnPause();
					musicPaused = false;
				}
				else if (!musicStarted)
				{
					music.Play();
					musicStarted = true;
				}
			}
			else if (music.isPlaying)
			{
				music.Pause();
				musicPaused = true;
			}
			if (active)
			{
				log(enabled ? "오디오 재생 시작" : "오디오 설정이 꺼져 있음");
			}
		}

		public void SetVolume(float normalizedVolume)
		{
			if (disposed)
			{
				return;
			}
			float num = (masterVolume = Mathf.Clamp01(normalizedVolume));
			music.volume = 0.58f * num * (float)ModOptions.Current.Music / 100f;
			effects.volume = 0.82f * num;
			if (num == 0f)
			{
				CombatVoice[] array = combatVoices;
				foreach (CombatVoice obj in array)
				{
					obj.Source.Stop();
					obj.Pending = null;
				}
			}
			UpdateCombatVoices();
		}

		private void StopCombatVoices()
		{
			CombatVoice[] array = combatVoices;
			foreach (CombatVoice obj in array)
			{
				obj.Source.Stop();
				obj.Pending = null;
				obj.Important = false;
				obj.PendingImportant = false;
				obj.Species = false;
				obj.PendingSpecies = false;
			}
			lastImpact = -1;
			lastHurtAt = -100f;
		}

		public void SetExpeditionActive(bool active, string profileId = "")
		{
			if (disposed)
			{
				return;
			}
			bool num = active && audioProfile != profileId;
			bool flag = !active && expeditionActive;
			if (num || flag)
			{
				audioProfile = profileId;
				hurtIndex = 0;
				StopCombatVoices();
			}
			if (expeditionActive != active)
			{
				expeditionActive = active;
				if (active)
				{
					hurtIndex = 0;
					lastImpact = -1;
					lastHurtAt = -100f;
				}
				SetMusicTrack(MusicCatalog.NextForMode(active, playlist));
			}
		}

		private void ReleaseClip(AudioClip clip)
		{
			if (!((Object)(object)clip == (Object)null) && !bundle.ReleaseAudio(clip))
			{
				Object.Destroy((Object)(object)clip);
			}
		}

		private void SetMusicTrack(int index)
		{
			if (disposed)
			{
				return;
			}
			index = Mathf.Clamp(index, 0, 8);
			if (index == musicTrackIndex && !MusicLoadFailed)
			{
				return;
			}
			musicTrackIndex = index;
			music.Stop();
			music.clip = null;
			if (clips.TryGetValue("music", out AudioClip value))
			{
				ReleaseClip(value);
			}
			clips.Remove("music");
			music.loop = !expeditionActive;
			musicStarted = false;
			musicPaused = false;
			MusicLoadFailed = false;
			try
			{
				AudioClip val = bundle.LoadAudio(Path.Combine(musicDirectory, MusicCatalog.FileNames[index]));
				clips["music"] = val;
				music.clip = val;
				if (overlayActive && soundEnabled)
				{
					music.Play();
					musicStarted = true;
				}
				log("Bundle music ready · " + MusicCatalog.FileNames[index] + " · " + val.length.ToString("0.0") + "s");
			}
			catch (Exception ex)
			{
				MusicLoadFailed = true;
				retryMusicAt = Time.unscaledTime + 2f;
				log("Bundle music failed · " + MusicCatalog.FileNames[index] + " · " + ex.Message);
			}
		}

		public void Tick()
		{
			if (disposed)
			{
				return;
			}
			UpdateCombatVoices();
			if (overlayActive && soundEnabled && !musicPaused && !IsMusicLoading)
			{
				if (MusicLoadFailed && Time.unscaledTime >= retryMusicAt)
				{
					SetMusicTrack(MusicCatalog.NextForMode(expeditionActive, playlist));
				}
				else if (!MusicLoadFailed && musicStarted && !music.isPlaying)
				{
					SetMusicTrack(MusicCatalog.NextForMode(expeditionActive, playlist));
				}
			}
		}

		public void PlayHover()
		{
			if (!(Time.unscaledTime - lastHoverSound < 0.09f))
			{
				lastHoverSound = Time.unscaledTime;
				Play("click", 0.22f);
			}
		}

		public void PlayUi()
		{
			Play("click", 0.8f);
		}

		public void PlayQuestComplete()
		{
			Play("quest_complete.ogg", 0.65f);
		}

		public void PlayAttack(bool critical)
		{
			Play(critical ? "player_critical.wav" : "player_normal.wav", 0.65f);
		}

		public void PlayHit(int speciesIndex, int impactId)
		{
			if (impactId == lastImpact)
			{
				return;
			}
			lastImpact = impactId;
			if (disposed || effects.mute)
			{
				return;
			}
			if (speciesIndex >= 0 && speciesIndex < CombatSoundCatalog.SpeciesAttacks.Length)
			{
				PlayCombat(CombatSoundCatalog.SpeciesAttacks[speciesIndex], 0.45f, important: false, species: true);
			}
			if (Time.unscaledTime - lastHurtAt < 0.08f)
			{
				return;
			}
			lastHurtAt = Time.unscaledTime;
			CombatVoice[] array = combatVoices;
			foreach (CombatVoice combatVoice in array)
			{
				if (combatVoice.Species)
				{
					combatVoice.DuckUntil = Time.unscaledTime + 0.12f;
				}
			}
			PlayCombat((hurtIndex++ % 2 == 0) ? "player_hurt_01.wav" : "player_hurt_02.wav", 0.55f, important: true, species: false);
		}

		public void PlayDeath()
		{
			Play("death", 0.9f);
		}

		public void PlayPortal()
		{
			Play("portal", 0.85f);
		}

		public void PlayLevelUp()
		{
			if (!(Time.unscaledTime - lastLevelUpSound < 0.5f))
			{
				lastLevelUpSound = Time.unscaledTime;
				Play("level_up.wav", 0.8f);
			}
		}

		public void PlaySkill(int index)
		{
			Play("skill" + (Mathf.Clamp(index, 0, 3) + 1), 0.9f);
		}

		private void Play(string name, float volume)
		{
			if (!disposed && !effects.mute && clips.TryGetValue(name, out AudioClip value))
			{
				int num;
				switch (name)
				{
				case "player_normal.wav":
				case "player_critical.wav":
					PlayCombat(name, volume, name == "player_critical.wav", species: false);
					return;
				default:
					num = ModOptions.Current.Sfx;
					break;
				case "level_up.wav":
					num = ModOptions.Current.LevelUp;
					break;
				case "click":
					num = ModOptions.Current.Ui;
					break;
				}
				int num2 = num;
				effects.PlayOneShot(value, Mathf.Min(1f, volume * 2f * (float)num2 / 100f));
			}
		}

		private void PlayCombat(string name, float gain, bool important, bool species)
		{
			if (disposed || effects.mute || masterVolume <= 0f || !clips.TryGetValue(name, out AudioClip value))
			{
				return;
			}
			CombatVoice combatVoice = null;
			CombatVoice[] array = combatVoices;
			foreach (CombatVoice combatVoice2 in array)
			{
				if (!combatVoice2.Source.isPlaying && (Object)(object)combatVoice2.Pending == (Object)null)
				{
					combatVoice = combatVoice2;
					break;
				}
			}
			if (combatVoice == null)
			{
				array = combatVoices;
				foreach (CombatVoice combatVoice3 in array)
				{
					if (!combatVoice3.Important && (Object)(object)combatVoice3.Pending == (Object)null && (combatVoice == null || combatVoice3.Started < combatVoice.Started))
					{
						combatVoice = combatVoice3;
					}
				}
				if (combatVoice != null)
				{
					combatVoice.Pending = value;
					combatVoice.PendingGain = gain;
					combatVoice.PendingImportant = important;
					combatVoice.PendingSpecies = species;
					combatVoice.ReplaceAt = Time.unscaledTime + 0.02f;
				}
			}
			else
			{
				combatVoice.Source.clip = value;
				combatVoice.Gain = gain;
				combatVoice.Important = important;
				combatVoice.Species = species;
				combatVoice.Started = Time.unscaledTime;
				combatVoice.DuckUntil = (species ? (Time.unscaledTime + 0.12f) : 0f);
				UpdateCombatVoices();
				combatVoice.Source.Play();
			}
		}

		private void UpdateCombatVoices()
		{
			float[] array = new float[combatVoices.Length];
			float num = 0f;
			for (int i = 0; i < combatVoices.Length; i++)
			{
				CombatVoice combatVoice = combatVoices[i];
				if (combatVoice == null)
				{
					continue;
				}
				float num2 = 1f;
				if ((Object)(object)combatVoice.Pending != (Object)null)
				{
					num2 = Mathf.Clamp01((combatVoice.ReplaceAt - Time.unscaledTime) / 0.02f);
					if (num2 == 0f)
					{
						combatVoice.Source.Stop();
						combatVoice.Source.clip = combatVoice.Pending;
						combatVoice.Pending = null;
						combatVoice.Gain = combatVoice.PendingGain;
						combatVoice.Important = combatVoice.PendingImportant;
						combatVoice.Species = combatVoice.PendingSpecies;
						combatVoice.DuckUntil = (combatVoice.Species ? (Time.unscaledTime + 0.12f) : 0f);
						combatVoice.Started = Time.unscaledTime;
						combatVoice.Source.Play();
						num2 = 1f;
					}
				}
				array[i] = 0.5f * ((float)ModOptions.Current.Hits / 100f) * combatVoice.Gain * num2 * ((combatVoice.Species && Time.unscaledTime < combatVoice.DuckUntil) ? 0.6f : 1f);
				if (combatVoice.Source.isPlaying)
				{
					num += array[i];
				}
			}
			float num3 = ((num > 0.92f) ? (0.92f / num) : 1f);
			for (int j = 0; j < combatVoices.Length; j++)
			{
				combatVoices[j].Source.volume = 0.82f * masterVolume * array[j] * num3;
			}
		}

		public void Dispose()
		{
			if (disposed)
			{
				return;
			}
			disposed = true;
			music.Stop();
			music.clip = null;
			effects.Stop();
			CombatVoice[] array = combatVoices;
			foreach (CombatVoice obj in array)
			{
				obj.Source.Stop();
				obj.Source.clip = null;
				obj.Pending = null;
			}
			foreach (AudioClip value in clips.Values)
			{
				ReleaseClip(value);
			}
			clips.Clear();
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
			}
		}

		private static AudioClip MakeTone(string name, float seconds, float from, float to, Wave wave, float gain)
		{
			int num = Math.Max(1, Mathf.RoundToInt(seconds * 22050f));
			float[] array = new float[num];
			double num2 = 0.0;
			for (int i = 0; i < num; i++)
			{
				float num3 = (float)i / (float)Math.Max(1, num - 1);
				float num4 = Mathf.Lerp(from, to, num3);
				num2 += (double)(num4 / 22050f);
				float num5 = Mathf.Sin(MathF.PI * Mathf.Clamp01(num3 / 0.06f)) * Mathf.Pow(1f - num3, 1.7f);
				array[i] = Sample(wave, num2) * num5 * gain;
			}
			AudioClip obj = AudioClip.Create(name, num, 1, 22050, false);
			obj.SetData(array, 0);
			return obj;
		}

		private static AudioClip MakeNoiseSweep(string name, float seconds, float gain)
		{
			int num = Math.Max(1, Mathf.RoundToInt(seconds * 22050f));
			float[] array = new float[num];
			Random random = new Random(713);
			float num2 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num3 = (float)i / (float)Math.Max(1, num - 1);
				num2 = num2 * 0.72f + ((float)random.NextDouble() * 2f - 1f) * 0.28f;
				array[i] = num2 * Mathf.Sin(MathF.PI * num3) * gain;
			}
			AudioClip obj = AudioClip.Create(name, num, 1, 22050, false);
			obj.SetData(array, 0);
			return obj;
		}

		private void LoadCombatEffects(string pluginDirectory, string[] files)
		{
			foreach (string text in files)
			{
				AudioClip val = bundle.LoadAudio(Path.Combine(pluginDirectory, "Assets", "Sounds", text));
				clips[text] = val;
				log("Bundle SFX ready · " + text + " · " + val.length.ToString("0.000") + "s");
			}
		}

		private void PlayVariant(string[] files, ref int nextIndex, float volume)
		{
			if (disposed || effects.mute)
			{
				return;
			}
			for (int i = 0; i < files.Length; i++)
			{
				string text = files[nextIndex];
				nextIndex = (nextIndex + 1) % files.Length;
				if (clips.ContainsKey(text))
				{
					Play(text, volume);
					break;
				}
			}
		}

		private static float Sample(Wave wave, double phase)
		{
			double num = phase - Math.Floor(phase);
			return wave switch
			{
				Wave.Square => (num < 0.5) ? 1 : (-1), 
				Wave.Triangle => (float)(1.0 - 4.0 * Math.Abs(num - 0.5)), 
				_ => (float)Math.Sin(phase * Math.PI * 2.0), 
			};
		}
	}
	public sealed class PocketExpeditionView : IDisposable
	{
		private sealed class BidirectionalScrollRect : ScrollRect, IPointerClickHandler, IEventSystemHandler
		{
			private bool manualDragging;

			private bool manualDragMoved;

			private InputButton manualDragButton;

			private Vector2 lastDragLocalPosition;

			public override void OnScroll(PointerEventData data)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)((ScrollRect)this).content == (Object)null || (Object)(object)((ScrollRect)this).viewport == (Object)null || Mathf.Abs(data.scrollDelta.y) < 0.001f)
				{
					((ScrollRect)this).OnScroll(data);
					return;
				}
				float num = Mathf.Clamp(Mathf.Abs(data.scrollDelta.y) * 0.08f, 0.04f, 0.25f);
				((ScrollRect)this).verticalNormalizedPosition = Mathf.Clamp01(((ScrollRect)this).verticalNormalizedPosition + ((data.scrollDelta.y > 0f) ? num : (0f - num)));
				((AbstractEventData)data).Use();
			}

			public override void OnBeginDrag(PointerEventData data