Decompiled source of SuperHornMod v2.1.1

SuperHornMod/SuperHornMod.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyCompany("SuperHornMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("SuperHornMod")]
[assembly: AssemblyTitle("SuperHornMod")]
[assembly: AssemblyVersion("1.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MyCoolMod
{
	public static class HornCreator
	{
		public static Sprite HornIcon;

		public static void Init()
		{
			LoadIcon();
			PrefabManager.OnVanillaPrefabsAvailable += CreateHorn;
			ItemManager.OnItemsRegistered += OnItemsRegistered;
		}

		private static void LoadIcon()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(MyMod.ModFolder, "horn_icon.png");
			if (!File.Exists(path))
			{
				Debug.LogWarning((object)"[Рог Хеймдалля] horn_icon.png не найден.");
				return;
			}
			byte[] array = File.ReadAllBytes(path);
			Texture2D val = new Texture2D(2, 2);
			ImageConversion.LoadImage(val, array);
			HornIcon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			Debug.Log((object)"[Рог Хеймдалля] Иконка загружена.");
		}

		private static void CreateHorn()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= CreateHorn;
			ItemConfig val = new ItemConfig();
			val.Name = Loc.GetRaw("item_name");
			val.Description = Loc.GetRaw("item_description");
			val.CraftingStation = CraftingStations.Workbench;
			val.MinStationLevel = 2;
			val.AddRequirement(new RequirementConfig("FineWood", 2, 0, true));
			val.AddRequirement(new RequirementConfig("TrophyEikthyr", 1, 0, true));
			val.AddRequirement(new RequirementConfig("LeatherScraps", 2, 1, true));
			val.AddRequirement(new RequirementConfig("Copper", 2, 0, true));
			val.AddRequirement(new RequirementConfig("Bronze", 0, 3, true));
			if ((Object)(object)HornIcon != (Object)null)
			{
				val.Icons = (Sprite[])(object)new Sprite[1] { HornIcon };
			}
			CustomItem val2 = new CustomItem("SuperHorn", "Club", val);
			ItemManager.Instance.AddItem(val2);
			Debug.Log((object)"[Рог Хеймдалля] Предмет зарегистрирован!");
		}

		private static void OnItemsRegistered()
		{
			ItemManager.OnItemsRegistered -= OnItemsRegistered;
			ReplaceModel();
		}

		private static void ReplaceModel()
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("SuperHorn");
			GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab("TankardAnniversary");
			if ((Object)(object)itemPrefab == (Object)null || (Object)(object)itemPrefab2 == (Object)null)
			{
				Debug.LogWarning((object)"[Рог Хеймдалля] Замена модели не удалась — префабы не найдены.");
				return;
			}
			Transform val = itemPrefab.transform.Find("attach");
			Transform val2 = itemPrefab2.transform.Find("attach");
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				Debug.LogWarning((object)"[Рог Хеймдалля] Transform 'attach' не найден.");
				return;
			}
			foreach (object item in val)
			{
				Transform val3 = (Transform)item;
				Object.Destroy((Object)(object)((Component)val3).gameObject);
			}
			GameObject val4 = Object.Instantiate<GameObject>(((Component)val2.GetChild(0)).gameObject, val);
			val4.transform.localPosition = Vector3.zero;
			val4.transform.localRotation = Quaternion.identity;
			val4.transform.localScale = Vector3.one;
			Debug.Log((object)"[Рог Хеймдалля] Модель заменена успешно.");
		}
	}
	[HarmonyPatch(typeof(Player), "LateUpdate")]
	public static class HornHandAdjust
	{
		private static readonly FieldInfo RightItemInstanceField = AccessTools.Field(typeof(VisEquipment), "m_rightItemInstance");

		private static bool logged;

		private static void Postfix(Player __instance)
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon();
			if (currentWeapon == null || (Object)(object)currentWeapon.m_dropPrefab == (Object)null || ((Object)currentWeapon.m_dropPrefab).name != "SuperHorn")
			{
				return;
			}
			VisEquipment component = ((Component)__instance).GetComponent<VisEquipment>();
			if ((Object)(object)component == (Object)null || RightItemInstanceField == null)
			{
				return;
			}
			object? value = RightItemInstanceField.GetValue(component);
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			if (!((Object)(object)val == (Object)null))
			{
				if (MyMod.DebugLogging != null && MyMod.DebugLogging.Value && !logged)
				{
					LogHierarchy(val.transform, "");
					logged = true;
				}
				val.transform.localPosition = new Vector3(0f, 0.05f, 0.05f);
				val.transform.localRotation = Quaternion.Euler(-10f, 0f, -100f);
				for (int i = 0; i < val.transform.childCount; i++)
				{
					Transform child = val.transform.GetChild(i);
					child.localPosition = Vector3.zero;
					child.localRotation = Quaternion.Euler(0f, 0f, 90f);
				}
			}
		}

		private static void LogHierarchy(Transform t, string indent)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Debug.Log((object)$"[Рог Хеймдалля] {indent}{((Object)t).name} pos={t.localPosition} rot={t.localEulerAngles} scale={t.localScale}");
			for (int i = 0; i < t.childCount; i++)
			{
				LogHierarchy(t.GetChild(i), indent + "  ");
			}
		}
	}
	[HarmonyPatch]
	public static class HornLogic
	{
		private const string RPC_HORN_SIGNAL = "HornOfHeimdall_Signal";

		private const float REPLY_WINDOW = 10f;

		private static Dictionary<HornSignalType, float> lastUseTime = new Dictionary<HornSignalType, float>();

		private static float globalLastUse = -999f;

		private static float lastReplyTime = -999f;

		private const float REPLY_COOLDOWN = 5f;

		private static float lastBuffTime = -999f;

		private static float lastHeardTime = -100f;

		private static HornSignalType lastHeardType = HornSignalType.Navigation;

		private static float lastBuffReceivedTime = -999f;

		private static ZRoutedRpc registeredOn;

		private static string cachedActivationKeyString;

		private static KeyCode cachedActivationKey = (KeyCode)103;

		private static void InitCooldowns()
		{
			lastUseTime.Clear();
			foreach (object value in Enum.GetValues(typeof(HornSignalType)))
			{
				HornSignalType key = (HornSignalType)value;
				lastUseTime[key] = -999f;
			}
			lastReplyTime = -999f;
			lastBuffTime = -999f;
		}

		private static bool IsOnCooldown(HornSignalType type, bool isReply, out float remaining)
		{
			float num = Time.time - globalLastUse;
			float value = MyMod.GlobalCooldown.Value;
			if (num < value)
			{
				remaining = value - num;
				return true;
			}
			if (isReply)
			{
				float num2 = Time.time - lastReplyTime;
				if (num2 < 5f)
				{
					remaining = 5f - num2;
					return true;
				}
				remaining = 0f;
				return false;
			}
			float num3 = (lastUseTime.ContainsKey(type) ? lastUseTime[type] : (-999f));
			float cooldown = HornSignalRegistry.GetConfig(type).Cooldown;
			float num4 = Time.time - num3;
			if (num4 < cooldown)
			{
				remaining = cooldown - num4;
				return true;
			}
			remaining = 0f;
			return false;
		}

		private static void StartCooldown(HornSignalType type, bool isReply)
		{
			globalLastUse = Time.time;
			if (isReply)
			{
				lastReplyTime = Time.time;
			}
			else
			{
				lastUseTime[type] = Time.time;
			}
		}

		private static bool IsBuffOnCooldown(out float remaining)
		{
			float num = Time.time - lastBuffTime;
			float value = MyMod.AlarmBuffCooldown.Value;
			if (num < value)
			{
				remaining = value - num;
				return true;
			}
			remaining = 0f;
			return false;
		}

		private static string GetSignalName(HornSignalType type)
		{
			return type switch
			{
				HornSignalType.Alarm => "Боевой сигнал", 
				HornSignalType.Navigation => "Сигнальный зов", 
				_ => type.ToString(), 
			};
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[HarmonyPostfix]
		private static void InitOnWorldLoad()
		{
			InitCooldowns();
			HornSignalRegistry.Init();
			RegisterRPC();
		}

		private static void RegisterRPC()
		{
			if (ZRoutedRpc.instance != null && registeredOn != ZRoutedRpc.instance)
			{
				ZRoutedRpc.instance.Register<Vector3, Vector3, int, bool>("HornOfHeimdall_Signal", (Method<Vector3, Vector3, int, bool>)OnSignalReceived);
				registeredOn = ZRoutedRpc.instance;
				Debug.Log((object)"[Рог Хеймдалля] RPC зарегистрирован.");
			}
		}

		private static void OnSignalReceived(long sender, Vector3 hornPos, Vector3 hornForward, int signalTypeInt, bool isReply)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				HornSignalConfig config = HornSignalRegistry.GetConfig((HornSignalType)signalTypeInt);
				float num = Vector3.Distance(hornPos, ((Component)localPlayer).transform.position);
				bool flag = num < 3f;
				HornSoundEngine.Play(hornPos, hornForward, (HornSignalType)signalTypeInt, isReply);
				if (!flag && config.ApplyBuff && num <= config.Radius)
				{
					TryApplyBuffToPlayer(localPlayer);
				}
				if (!flag && num <= config.Radius)
				{
					lastHeardTime = Time.time;
					lastHeardType = (HornSignalType)signalTypeInt;
					string text = ((!isReply || config.ReplyMessage == null) ? string.Format(config.HeardMessage, num.ToString("F0"), MyMod.ActivationKey.Value) : config.ReplyMessage);
					((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		[HarmonyPostfix]
		private static void HornInput(Player __instance)
		{
			//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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			if (cachedActivationKeyString != MyMod.ActivationKey.Value)
			{
				if (!Enum.TryParse<KeyCode>(MyMod.ActivationKey.Value, ignoreCase: true, out cachedActivationKey))
				{
					cachedActivationKey = (KeyCode)103;
					Debug.LogWarning((object)("[Рог Хеймдалля] Неверная клавиша активации в конфиге ('" + MyMod.ActivationKey.Value + "'), использую G."));
				}
				cachedActivationKeyString = MyMod.ActivationKey.Value;
			}
			KeyCode val = cachedActivationKey;
			if (!Input.GetKeyDown(val))
			{
				return;
			}
			ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon();
			if (currentWeapon == null || (Object)(object)currentWeapon.m_dropPrefab == (Object)null || ((Object)currentWeapon.m_dropPrefab).name != "SuperHorn")
			{
				return;
			}
			HornSignalType hornSignalType = HornSignalType.Navigation;
			if (Input.GetKey((KeyCode)304))
			{
				hornSignalType = HornSignalType.Alarm;
			}
			bool flag = Time.time - lastHeardTime < 10f;
			if (flag)
			{
				hornSignalType = lastHeardType;
			}
			HornSignalConfig config = HornSignalRegistry.GetConfig(hornSignalType);
			if (IsOnCooldown(hornSignalType, flag, out var remaining))
			{
				((Character)__instance).Message((MessageType)2, Loc.Get("cooldown_generic", remaining), 0, (Sprite)null, false);
				return;
			}
			if (hornSignalType == HornSignalType.Alarm && config.ApplyBuff && IsBuffOnCooldown(out var remaining2))
			{
				((Character)__instance).Message((MessageType)2, Loc.Get("buff_cooldown_input", remaining2), 0, (Sprite)null, false);
				return;
			}
			if (currentWeapon.m_durability < config.DurabilityCost)
			{
				((Character)__instance).Message((MessageType)2, Loc.Get("horn_worn_out"), 0, (Sprite)null, false);
				return;
			}
			if (config.StaminaCost > 0f && !((Character)__instance).HaveStamina(config.StaminaCost))
			{
				((Character)__instance).Message((MessageType)2, Loc.Get("not_enough_stamina"), 0, (Sprite)null, false);
				return;
			}
			StartCooldown(hornSignalType, flag);
			currentWeapon.m_durability -= config.DurabilityCost;
			if (config.StaminaCost > 0f)
			{
				((Character)__instance).UseStamina(config.StaminaCost);
			}
			if (flag)
			{
				lastHeardTime = -100f;
			}
			((MonoBehaviour)__instance).StartCoroutine(ActivateHorn(__instance, hornSignalType, flag));
		}

		private static IEnumerator ActivateHorn(Player player, HornSignalType signalType, bool isReply)
		{
			HornSignalConfig config = HornSignalRegistry.GetConfig(signalType);
			player.StartEmote(config.Emote, true);
			yield return (object)new WaitForSeconds(0.35f);
			if (ZRoutedRpc.instance != null)
			{
				Vector3 pos = ((Component)player).transform.position + Vector3.up * 1.8f;
				Vector3 forward = ((Component)player).transform.forward;
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "HornOfHeimdall_Signal", new object[4]
				{
					pos,
					forward,
					(int)signalType,
					isReply
				});
				if (config.ApplyBuff)
				{
					TryApplyBuffToPlayer(player);
				}
				((Character)player).Message((MessageType)2, isReply ? Loc.GetRaw("activate_reply") : config.ActivateMessage, 0, (Sprite)null, false);
			}
		}

		private static void TryApplyBuffToPlayer(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			SEMan sEMan = ((Character)player).GetSEMan();
			StatusEffect val = sEMan.GetStatusEffects().Find((StatusEffect se) => ((Object)se).name == "SE_HornBuff");
			if ((Object)(object)val != (Object)null)
			{
				Debug.Log((object)"[Рог Хеймдалля] Баф уже активен — не обновляем.");
				return;
			}
			float num = Time.time - lastBuffReceivedTime;
			float value = MyMod.AlarmBuffCooldown.Value;
			if (num < value)
			{
				float num2 = value - num;
				Debug.Log((object)$"[Рог Хеймдалля] Баф на кулдауне — {num2:F0} сек.");
				((Character)player).Message((MessageType)1, Loc.Get("buff_cooldown_apply", num2), 0, (Sprite)null, false);
			}
			else
			{
				SE_HornBuff sE_HornBuff = ScriptableObject.CreateInstance<SE_HornBuff>();
				((Object)sE_HornBuff).name = "SE_HornBuff";
				sEMan.AddStatusEffect((StatusEffect)(object)sE_HornBuff, false, 0, 0f, (short)(-1));
				lastBuffReceivedTime = Time.time;
				lastBuffTime = Time.time;
				Debug.Log((object)("[Рог Хеймдалля] Баф наложен на " + ((Character)player).GetHoverName() + "."));
			}
		}
	}
	public class HornSignalConfig
	{
		public string Name;

		public float Radius;

		public float Cooldown;

		public float DurabilityCost;

		public float StaminaCost;

		public string SoundFile;

		public string ReplySoundFile;

		public bool ApplyBuff;

		public bool AffectsEnemies;

		public bool AffectsAllies;

		public float EnemyScareRadius;

		public string Emote;

		public string ActivateMessage;

		public string HeardMessage;

		public string ReplyMessage;
	}
	public static class HornSignalRegistry
	{
		public static Dictionary<HornSignalType, HornSignalConfig> Configs = new Dictionary<HornSignalType, HornSignalConfig>();

		private static Dictionary<string, AudioClip> loadedClips = new Dictionary<string, AudioClip>();

		public static void Init()
		{
			RegisterSignals();
			LoadAllSounds();
			Debug.Log((object)$"[Рог Хеймдалля] Зарегистрировано {Configs.Count} типов сигналов.");
		}

		private static void RegisterSignals()
		{
			Configs.Clear();
			Configs[HornSignalType.Navigation] = new HornSignalConfig
			{
				Name = "Сигнальный зов",
				Radius = MyMod.NavRadius.Value,
				Cooldown = MyMod.NavCooldown.Value,
				DurabilityCost = MyMod.NavDurabilityCost.Value,
				StaminaCost = 0f,
				SoundFile = "horn.wav",
				ReplySoundFile = "horn_reply.wav",
				ApplyBuff = false,
				AffectsEnemies = false,
				AffectsAllies = true,
				EnemyScareRadius = 0f,
				Emote = "cheer",
				ActivateMessage = "Сигнальный зов!",
				HeardMessage = "Слышен рог! ({0}м) [Нажми {1} чтобы ответить]",
				ReplyMessage = "Ответный сигнал!"
			};
			Configs[HornSignalType.Alarm] = new HornSignalConfig
			{
				Name = "Боевой сигнал",
				Radius = MyMod.AlarmRadius.Value,
				Cooldown = MyMod.AlarmCooldown.Value,
				DurabilityCost = MyMod.AlarmDurabilityCost.Value,
				StaminaCost = MyMod.AlarmStaminaCost.Value,
				SoundFile = "horn_alarm.wav",
				ReplySoundFile = null,
				ApplyBuff = true,
				AffectsEnemies = true,
				AffectsAllies = true,
				EnemyScareRadius = MyMod.AlarmScareRadius.Value,
				Emote = "challenge",
				ActivateMessage = "БОЕВОЙ СИГНАЛ!",
				HeardMessage = "Боевой сигнал! ({0}м)",
				ReplyMessage = null
			};
		}

		private static void LoadAllSounds()
		{
			loadedClips.Clear();
			foreach (KeyValuePair<HornSignalType, HornSignalConfig> config in Configs)
			{
				LoadClipIfNeeded(config.Value.SoundFile);
				if (config.Value.ReplySoundFile != null)
				{
					LoadClipIfNeeded(config.Value.ReplySoundFile);
				}
			}
		}

		private static void LoadClipIfNeeded(string fileName)
		{
			if (string.IsNullOrEmpty(fileName) || loadedClips.ContainsKey(fileName))
			{
				return;
			}
			string path = Path.Combine(MyMod.ModFolder, fileName);
			if (!File.Exists(path))
			{
				Debug.LogWarning((object)("[Рог Хеймдалля] " + fileName + " не найден."));
				return;
			}
			AudioClip val = WavLoader.LoadWav(path);
			if ((Object)(object)val != (Object)null)
			{
				loadedClips[fileName] = val;
				Debug.Log((object)("[Рог Хеймдалля] " + fileName + " загружен."));
			}
		}

		public static AudioClip GetClip(HornSignalType type, bool isReply)
		{
			if (!Configs.ContainsKey(type))
			{
				return null;
			}
			HornSignalConfig hornSignalConfig = Configs[type];
			AudioClip value = null;
			if (isReply && hornSignalConfig.ReplySoundFile != null && loadedClips.TryGetValue(hornSignalConfig.ReplySoundFile, out value))
			{
				return value;
			}
			AudioClip value2 = null;
			if (hornSignalConfig.SoundFile != null && loadedClips.TryGetValue(hornSignalConfig.SoundFile, out value2))
			{
				return value2;
			}
			AudioClip value3 = null;
			if (type != HornSignalType.Navigation && loadedClips.TryGetValue("horn.wav", out value3))
			{
				return value3;
			}
			return null;
		}

		public static HornSignalConfig GetConfig(HornSignalType type)
		{
			return Configs.ContainsKey(type) ? Configs[type] : Configs[HornSignalType.Navigation];
		}
	}
	public enum HornSignalType
	{
		Navigation,
		Alarm
	}
	public static class HornSoundEngine
	{
		public static void Play(Vector3 hornPos, Vector3 hornForward, HornSignalType signalType, bool isReply)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			HornSignalConfig config = HornSignalRegistry.GetConfig(signalType);
			Vector3 position = ((Component)localPlayer).transform.position;
			float num = Vector3.Distance(hornPos, position);
			bool flag = num < 3f;
			float num2 = config.Radius;
			if (!MyMod.IsArcade)
			{
				float num3 = Mathf.Clamp((hornPos.y - position.y) / 40f, -0.4f, 0.4f);
				num2 *= 1f + num3;
				num2 *= GetWeatherMultiplier();
			}
			if (flag || !(num > num2))
			{
				Vector3 val = position - hornPos;
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				float num4 = Vector3.Dot(((Vector3)(ref hornForward)).normalized, normalized);
				float directionMul = (MyMod.IsArcade ? 1f : Mathf.Lerp(0.3f, 1f, (num4 + 1f) / 2f));
				if (flag)
				{
					directionMul = 1f;
				}
				bool flag2 = false;
				if (!flag && !MyMod.IsArcade)
				{
					flag2 = Physics.Raycast(hornPos, normalized, num, LayerMask.GetMask(new string[2] { "Default", "terrain" }));
				}
				float headMul = 1f;
				if (MyMod.IsSimulation && !flag)
				{
					val = hornPos - position;
					Vector3 normalized2 = ((Vector3)(ref val)).normalized;
					float num5 = Vector3.Dot(((Component)localPlayer).transform.forward, normalized2);
					headMul = Mathf.Lerp(0.85f, 1.1f, (num5 + 1f) / 2f);
				}
				float echoStrength = 0.5f;
				if (MyMod.IsSimulation && !flag)
				{
					echoStrength = CalculateSpaceOpenness(hornPos, hornForward);
				}
				float weatherCutoffMul = 1f;
				if (!MyMod.IsArcade)
				{
					float weatherMultiplier = GetWeatherMultiplier();
					weatherCutoffMul = Mathf.Lerp(1f, 0.7f, 1f - weatherMultiplier);
				}
				float dist = (flag ? 0f : Mathf.Clamp01(num / num2));
				SoundContext ctx = new SoundContext
				{
					hornPos = hornPos,
					listenerPos = position,
					hornForward = hornForward,
					distance = num,
					dist01 = dist,
					directionMul = directionMul,
					headMul = headMul,
					isSelf = flag,
					isReply = isReply,
					obstructed = flag2,
					echoStrength = echoStrength,
					weatherCutoffMul = weatherCutoffMul,
					signalType = signalType
				};
				SpawnSound(ctx);
				SpawnVFX(hornPos);
				if (MyMod.IsSimulation && flag2 && !flag && num > 30f && (Object)(object)GameCamera.instance != (Object)null)
				{
					float delay = Random.Range(0.5f, 0.8f);
					((MonoBehaviour)GameCamera.instance).StartCoroutine(PlayAcousticShadow(ctx, delay));
				}
				if (config.AffectsEnemies && config.EnemyScareRadius > 0f)
				{
					AffectNearbyCreatures(hornPos, config.EnemyScareRadius);
				}
			}
		}

		private static void SpawnSound(SoundContext ctx)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			AudioClip clip = HornSignalRegistry.GetClip(ctx.signalType, ctx.isReply);
			if ((Object)(object)clip == (Object)null)
			{
				return;
			}
			GameObject val = new GameObject("HeimdallHornSound");
			val.transform.position = ctx.hornPos;
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.clip = clip;
			val2.spatialBlend = (ctx.isSelf ? 0.4f : 1f);
			val2.minDistance = 5f;
			val2.maxDistance = HornSignalRegistry.GetConfig(ctx.signalType).Radius * 1.2f;
			val2.rolloffMode = (AudioRolloffMode)1;
			val2.spread = (ctx.isSelf ? 120f : 30f);
			val2.dopplerLevel = 0f;
			float num = ctx.directionMul * ctx.headMul;
			if (ctx.obstructed)
			{
				num *= (MyMod.IsSimulation ? 0.3f : 0.5f);
			}
			if (!ctx.isSelf && ctx.distance > 50f)
			{
				float num2 = Mathf.Clamp01((ctx.distance - 50f) / 100f);
				num *= Mathf.Lerp(1f, 0.15f, num2);
			}
			num *= MyMod.MasterVolume.Value;
			val2.volume = Mathf.Clamp01(num);
			if (!MyMod.IsArcade)
			{
				AudioLowPassFilter val3 = val.AddComponent<AudioLowPassFilter>();
				if (ctx.isSelf)
				{
					val3.cutoffFrequency = 22000f;
				}
				else
				{
					float num3 = 50f;
					float num4 = 150f;
					float num5 = Mathf.Clamp01((ctx.distance - num3) / (num4 - num3));
					float num6 = Mathf.Lerp(14000f, 800f, num5 * num5);
					if (ctx.obstructed)
					{
						num6 = Mathf.Min(num6, MyMod.IsSimulation ? 1200f : 1800f);
					}
					num6 *= ctx.weatherCutoffMul;
					val3.cutoffFrequency = Mathf.Max(num6, 500f);
				}
				val3.lowpassResonanceQ = 1f;
			}
			val2.Play();
			if (!MyMod.IsArcade && !ctx.isSelf && ctx.distance > 50f)
			{
				float delay = ctx.distance / 343f;
				float num7 = val2.volume * 0.3f * ctx.echoStrength;
				if (num7 > 0.02f && (Object)(object)GameCamera.instance != (Object)null)
				{
					((MonoBehaviour)GameCamera.instance).StartCoroutine(PlayEcho(ctx.hornPos, clip, delay, num7, ctx.dist01, HornSignalRegistry.GetConfig(ctx.signalType).Radius));
				}
			}
			Object.Destroy((Object)(object)val, clip.length + 3f);
		}

		private static IEnumerator PlayEcho(Vector3 pos, AudioClip clip, float delay, float vol, float dist01, float maxDist)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			yield return (object)new WaitForSeconds(delay);
			GameObject go = new GameObject("HeimdallHornEcho");
			go.transform.position = pos;
			AudioSource src = go.AddComponent<AudioSource>();
			src.clip = clip;
			src.spatialBlend = 1f;
			src.minDistance = 5f;
			src.maxDistance = maxDist;
			src.rolloffMode = (AudioRolloffMode)1;
			src.spread = 80f;
			src.dopplerLevel = 0f;
			src.volume = vol;
			src.pitch = 0.95f;
			AudioLowPassFilter lp = go.AddComponent<AudioLowPassFilter>();
			lp.cutoffFrequency = Mathf.Lerp(3000f, 1000f, dist01);
			lp.lowpassResonanceQ = 1f;
			src.Play();
			Object.Destroy((Object)(object)go, clip.length + 1f);
		}

		private static IEnumerator PlayAcousticShadow(SoundContext ctx, float delay)
		{
			yield return (object)new WaitForSeconds(delay);
			AudioClip clip = HornSignalRegistry.GetClip(ctx.signalType, ctx.isReply);
			if (!((Object)(object)clip == (Object)null))
			{
				Vector3 val = new Vector3(Random.Range(-1f, 1f), Random.Range(0.2f, 0.5f), Random.Range(-1f, 1f));
				Vector3 offset = ((Vector3)(ref val)).normalized * Random.Range(15f, 25f);
				GameObject go = new GameObject("HeimdallHornShadow");
				go.transform.position = ctx.hornPos + offset;
				AudioSource src = go.AddComponent<AudioSource>();
				src.clip = clip;
				src.spatialBlend = 1f;
				src.minDistance = 5f;
				src.maxDistance = HornSignalRegistry.GetConfig(ctx.signalType).Radius * 0.6f;
				src.rolloffMode = (AudioRolloffMode)1;
				src.spread = 120f;
				src.dopplerLevel = 0f;
				src.volume = ctx.directionMul * 0.4f;
				src.pitch = 0.92f;
				AudioLowPassFilter lp = go.AddComponent<AudioLowPassFilter>();
				lp.cutoffFrequency = 1500f;
				lp.lowpassResonanceQ = 1.2f;
				src.Play();
				Object.Destroy((Object)(object)go, clip.length + 1f);
			}
		}

		private static void AffectNearbyCreatures(Vector3 pos, float enemyRadius)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			float value = MyMod.AlarmScareRadius.Value;
			float num = Mathf.Max(enemyRadius, value);
			int num2 = 0;
			int num3 = 0;
			foreach (BaseAI allInstance in BaseAI.GetAllInstances())
			{
				if ((Object)(object)allInstance == (Object)null)
				{
					continue;
				}
				float num4 = Vector3.Distance(pos, ((Component)allInstance).transform.position);
				if (num4 > num)
				{
					continue;
				}
				try
				{
					Character component = ((Component)allInstance).GetComponent<Character>();
					if (!((Object)(object)component == (Object)null) && !component.IsDead() && !component.IsTamed())
					{
						AnimalAI val = (AnimalAI)(object)((allInstance is AnimalAI) ? allInstance : null);
						if ((Object)(object)val != (Object)null && num4 <= value)
						{
							allInstance.Alert();
							num3++;
						}
						else if ((Object)(object)val == (Object)null && num4 <= enemyRadius)
						{
							allInstance.Alert();
							allInstance.SetAggravated(true, (AggravatedReason)0);
							num2++;
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("[Рог Хеймдалля] Ошибка: " + ex.Message));
				}
			}
			Debug.Log((object)$"[Рог Хеймдалля] Боевой сигнал: {num2} врагов встревожено, {num3} животных напугано.");
		}

		private static float GetWeatherMultiplier()
		{
			if ((Object)(object)EnvMan.instance == (Object)null)
			{
				return 1f;
			}
			float windIntensity = EnvMan.instance.GetWindIntensity();
			bool flag = false;
			EnvSetup currentEnvironment = EnvMan.instance.GetCurrentEnvironment();
			if (currentEnvironment != null)
			{
				string text = currentEnvironment.m_name.ToLower();
				flag = text.Contains("rain") || text.Contains("thunder") || text.Contains("storm");
			}
			float num = 1f;
			if (flag)
			{
				num *= 0.8f;
			}
			if (windIntensity > 0.5f)
			{
				num *= Mathf.Lerp(1f, 0.85f, (windIntensity - 0.5f) * 2f);
			}
			return num;
		}

		private static float CalculateSpaceOpenness(Vector3 pos, Vector3 forward)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_008f: 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)
			Vector3 val = Vector3.Cross(forward, Vector3.up);
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			Vector3[] obj = new Vector3[6]
			{
				Vector3.up,
				((Vector3)(ref forward)).normalized,
				-((Vector3)(ref forward)).normalized,
				normalized,
				-normalized,
				default(Vector3)
			};
			val = forward + Vector3.up;
			obj[5] = ((Vector3)(ref val)).normalized;
			Vector3[] array = (Vector3[])(object)obj;
			int num = 0;
			Vector3[] array2 = array;
			foreach (Vector3 val2 in array2)
			{
				if (!Physics.Raycast(pos, val2, 50f, LayerMask.GetMask(new string[2] { "Default", "terrain" })))
				{
					num++;
				}
			}
			return (float)num / (float)array.Length;
		}

		private static void SpawnVFX(Vector3 pos)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab("vfx_WishbonePing");
			if (!((Object)(object)prefab == (Object)null))
			{
				bool activeSelf = prefab.activeSelf;
				prefab.SetActive(false);
				GameObject val = Object.Instantiate<GameObject>(prefab, pos, Quaternion.identity);
				prefab.SetActive(activeSelf);
				ZNetView component = val.GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)component);
				}
				val.SetActive(true);
				Object.Destroy((Object)(object)val, 5f);
			}
		}
	}
	public static class Loc
	{
		private static readonly Dictionary<string, string> En = new Dictionary<string, string>
		{
			["item_name"] = "Horn of Heimdall",
			["item_description"] = "An ancient horn of Bifrost's guardian.\nG - navigation call\nShift+G - battle alarm",
			["signal_navigation_name"] = "Navigation Call",
			["signal_alarm_name"] = "Battle Alarm",
			["activate_navigation"] = "Navigation call!",
			["activate_alarm"] = "BATTLE ALARM!",
			["activate_reply"] = "Reply signal!",
			["heard_navigation"] = "A horn call! ({0}m) [Press {1} to reply]",
			["heard_alarm"] = "Battle alarm! ({0}m)",
			["reply_navigation"] = "Reply signal!",
			["cooldown_generic"] = "Catching your breath... ({0:F0}s)",
			["buff_cooldown_input"] = "Battle spirit hasn't recovered yet... ({0:F0}s)",
			["buff_cooldown_apply"] = "Battle spirit hasn't recovered yet ({0:F0}s)",
			["horn_worn_out"] = "The horn is too worn out!",
			["not_enough_stamina"] = "Not enough stamina!",
			["buff_name"] = "Battle Horn",
			["buff_tooltip_header"] = "The spirit of war fills you!\n",
			["buff_tooltip_stamina_regen"] = "+{0:F0}% stamina regen\n",
			["buff_tooltip_stamina_drain"] = "-{0:F0}% stamina drain\n",
			["buff_tooltip_adrenaline_instant"] = "+{0:F0} instant adrenaline\n",
			["buff_tooltip_adrenaline_gain"] = "+{0:F0}% adrenaline gain"
		};

		private static readonly Dictionary<string, string> Ru = new Dictionary<string, string>
		{
			["item_name"] = "Рог Хеймдалля",
			["item_description"] = "Древний рог стража Биврёста.\nG — сигнальный зов\nShift+G — боевой сигнал",
			["signal_navigation_name"] = "Сигнальный зов",
			["signal_alarm_name"] = "Боевой сигнал",
			["activate_navigation"] = "Сигнальный зов!",
			["activate_alarm"] = "БОЕВОЙ СИГНАЛ!",
			["activate_reply"] = "Ответный сигнал!",
			["heard_navigation"] = "Слышен рог! ({0}м) [Нажми {1} чтобы ответить]",
			["heard_alarm"] = "Боевой сигнал! ({0}м)",
			["reply_navigation"] = "Ответный сигнал!",
			["cooldown_generic"] = "Надо перевести дыхание... ({0:F0} сек)",
			["buff_cooldown_input"] = "Боевой дух ещё не восстановился... ({0:F0} сек)",
			["buff_cooldown_apply"] = "Боевой дух ещё не восстановился ({0:F0} сек)",
			["horn_worn_out"] = "Рог слишком изношен!",
			["not_enough_stamina"] = "Недостаточно выносливости!",
			["buff_name"] = "Боевой рог",
			["buff_tooltip_header"] = "Воинский дух наполняет тебя!\n",
			["buff_tooltip_stamina_regen"] = "+{0:F0}% реген выносливости\n",
			["buff_tooltip_stamina_drain"] = "-{0:F0}% расход выносливости\n",
			["buff_tooltip_adrenaline_instant"] = "+{0:F0} адреналин мгновенно\n",
			["buff_tooltip_adrenaline_gain"] = "+{0:F0}% набор адреналина"
		};

		private static bool IsRussian()
		{
			try
			{
				return PlayerPrefs.GetString("language", "English") == "Russian";
			}
			catch
			{
				return false;
			}
		}

		public static string GetRaw(string key)
		{
			Dictionary<string, string> dictionary = (IsRussian() ? Ru : En);
			if (!dictionary.TryGetValue(key, out var value))
			{
				return key;
			}
			return value;
		}

		public static string Get(string key, params object[] args)
		{
			string raw = GetRaw(key);
			return (args != null && args.Length != 0) ? string.Format(raw, args) : raw;
		}
	}
	[BepInPlugin("com.rodogor.hornofheimdall", "Рог Хеймдалля", "2.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class MyMod : BaseUnityPlugin
	{
		public static ConfigEntry<string> ActivationKey;

		public static ConfigEntry<string> HornMode;

		public static ConfigEntry<float> GlobalCooldown;

		public static ConfigEntry<float> MasterVolume;

		public static ConfigEntry<float> NavRadius;

		public static ConfigEntry<float> NavCooldown;

		public static ConfigEntry<float> NavDurabilityCost;

		public static ConfigEntry<float> AlarmRadius;

		public static ConfigEntry<float> AlarmCooldown;

		public static ConfigEntry<float> AlarmDurabilityCost;

		public static ConfigEntry<float> AlarmStaminaCost;

		public static ConfigEntry<float> AlarmBuffDuration;

		public static ConfigEntry<float> AlarmBuffCooldown;

		public static ConfigEntry<float> AlarmStaminaRegenBonus;

		public static ConfigEntry<float> AlarmStaminaDrainReduction;

		public static ConfigEntry<float> AlarmAdrenalineInstant;

		public static ConfigEntry<float> AlarmAdrenalineGainBonus;

		public static ConfigEntry<float> AlarmScareRadius;

		public static ConfigEntry<bool> DebugLogging;

		public static Sprite HornBuffIcon;

		public static string ModFolder;

		public static bool IsArcade => HornMode.Value == "Arcade";

		public static bool IsRealistic => HornMode.Value == "Realistic";

		public static bool IsSimulation => HornMode.Value == "Simulation";

		private void Awake()
		{
			ModFolder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			Debug.Log((object)("[Рог Хеймдалля] Папка мода: " + ModFolder));
			ActivationKey = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ActivationKey", "G", "Key used to blow the horn");
			HornMode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "HornMode", "Simulation", "Sound behaviour: Arcade / Realistic / Simulation");
			GlobalCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GlobalCooldown", 3f, "Global cooldown between any two signals (sec)");
			MasterVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "MasterVolume", 0.5f, "Overall horn volume (0.0 - 1.0)");
			NavRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Navigation Call", "Radius", 300f, "Navigation call radius (m)");
			NavCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Navigation Call", "Cooldown", 20f, "Navigation call cooldown (sec)");
			NavDurabilityCost = ((BaseUnityPlugin)this).Config.Bind<float>("Navigation Call", "DurabilityCost", 3f, "Durability cost per navigation call");
			AlarmRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "Radius", 50f, "Battle alarm radius (m)");
			AlarmCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "Cooldown", 60f, "Battle alarm cooldown (sec)");
			AlarmDurabilityCost = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "DurabilityCost", 8f, "Durability cost per battle alarm");
			AlarmStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "StaminaCost", 20f, "Stamina cost per battle alarm");
			AlarmBuffDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "BuffDuration", 60f, "Battle buff duration (sec)");
			AlarmBuffCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "BuffCooldown", 120f, "Buff cooldown - cannot be refreshed until it passes (sec)");
			AlarmStaminaRegenBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "StaminaRegenBonus", 0.3f, "Stamina regen bonus (+30% = 0.30)");
			AlarmStaminaDrainReduction = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "StaminaDrainReduction", 0.3f, "Stamina drain reduction (-30% = 0.30)");
			AlarmAdrenalineInstant = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "AdrenalineInstant", 25f, "Instant adrenaline on activation");
			AlarmAdrenalineGainBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "AdrenalineGainBonus", 0.4f, "Adrenaline gain bonus (+40% = 0.40)");
			AlarmScareRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Battle Alarm", "ScareRadius", 40f, "Radius for scaring wild animals (m)");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Verbose debug logging (e.g. hand-position hierarchy)");
			LoadBuffIcon();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
			HornCreator.Init();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Рог Хеймдалля загружен!");
		}

		private void LoadBuffIcon()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(ModFolder, "horn_buff_icon.png");
			if (!File.Exists(path))
			{
				Debug.LogWarning((object)"[Рог Хеймдалля] horn_buff_icon.png не найден!");
				return;
			}
			byte[] array = File.ReadAllBytes(path);
			Texture2D val = new Texture2D(2, 2);
			ImageConversion.LoadImage(val, array);
			HornBuffIcon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			Debug.Log((object)"[Рог Хеймдалля] Иконка бафа загружена.");
		}
	}
	public class SE_HornBuff : SE_Stats
	{
		public override void Setup(Character character)
		{
			base.m_staminaRegenMultiplier = 1f + MyMod.AlarmStaminaRegenBonus.Value;
			base.m_runStaminaDrainModifier = 0f - MyMod.AlarmStaminaDrainReduction.Value;
			base.m_adrenalineUpFront = MyMod.AlarmAdrenalineInstant.Value;
			base.m_adrenalineModifier = MyMod.AlarmAdrenalineGainBonus.Value;
			((StatusEffect)this).m_ttl = MyMod.AlarmBuffDuration.Value;
			((StatusEffect)this).m_name = "Боевой рог";
			((StatusEffect)this).m_tooltip = "Воинский дух наполняет тебя!\n" + $"+{MyMod.AlarmStaminaRegenBonus.Value * 100f:F0}% реген выносливости\n" + $"-{MyMod.AlarmStaminaDrainReduction.Value * 100f:F0}% расход выносливости\n" + $"+{MyMod.AlarmAdrenalineInstant.Value:F0} адреналин мгновенно\n" + $"+{MyMod.AlarmAdrenalineGainBonus.Value * 100f:F0}% набор адреналина";
			((StatusEffect)this).m_icon = MyMod.HornBuffIcon;
			((SE_Stats)this).Setup(character);
			Debug.Log((object)("[Рог Хеймдалля] Боевой баф наложен на " + character.GetHoverName() + ": " + $"стамина ×{base.m_staminaRegenMultiplier:F2}, " + $"адреналин +{base.m_adrenalineUpFront:F0}"));
		}
	}
	public struct SoundContext
	{
		public Vector3 hornPos;

		public Vector3 listenerPos;

		public Vector3 hornForward;

		public float distance;

		public float dist01;

		public float directionMul;

		public float headMul;

		public bool isSelf;

		public bool isReply;

		public bool obstructed;

		public float echoStrength;

		public float weatherCutoffMul;

		public HornSignalType signalType;
	}
	public static class WavLoader
	{
		public static AudioClip LoadWav(string path)
		{
			try
			{
				byte[] array = File.ReadAllBytes(path);
				if (array.Length < 12 || array[0] != 82 || array[1] != 73 || array[2] != 70 || array[3] != 70 || array[8] != 87 || array[9] != 65 || array[10] != 86 || array[11] != 69)
				{
					Debug.LogWarning((object)("[Рог Хеймдалля] " + Path.GetFileName(path) + ": не RIFF/WAVE файл."));
					return null;
				}
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = -1;
				int num5 = 0;
				int num6 = 12;
				while (num6 + 8 <= array.Length)
				{
					char c = (char)array[num6];
					char c2 = (char)array[num6 + 1];
					char c3 = (char)array[num6 + 2];
					char c4 = (char)array[num6 + 3];
					int num7 = BitConverter.ToInt32(array, num6 + 4);
					int num8 = num6 + 8;
					bool flag = c == 'f' && c2 == 'm' && c3 == 't' && c4 == ' ';
					bool flag2 = c == 'd' && c2 == 'a' && c3 == 't' && c4 == 'a';
					if (flag && num8 + 16 <= array.Length)
					{
						num = BitConverter.ToInt16(array, num8 + 2);
						num2 = BitConverter.ToInt32(array, num8 + 4);
						num3 = BitConverter.ToInt16(array, num8 + 14);
					}
					else if (flag2)
					{
						num4 = num8;
						num5 = num7;
					}
					if (num7 < 0)
					{
						break;
					}
					num6 = num8 + num7 + num7 % 2;
				}
				if (num4 < 0 || num <= 0 || num2 <= 0)
				{
					Debug.LogWarning((object)("[Рог Хеймдалля] " + Path.GetFileName(path) + ": не найден корректный chunk 'fmt ' или 'data'."));
					return null;
				}
				if (num3 != 16)
				{
					Debug.LogWarning((object)$"[Рог Хеймдалля] {Path.GetFileName(path)}: поддерживается только 16-bit PCM, а тут {num3}-bit. Файл пропущен.");
					return null;
				}
				if (num4 + num5 > array.Length)
				{
					num5 = array.Length - num4;
				}
				int num9 = num5 / 2;
				if (num9 <= 0)
				{
					Debug.LogWarning((object)("[Рог Хеймдалля] " + Path.GetFileName(path) + ": пустой data-chunk."));
					return null;
				}
				float[] array2 = new float[num9];
				for (int i = 0; i < num9; i++)
				{
					short num10 = BitConverter.ToInt16(array, num4 + i * 2);
					array2[i] = (float)num10 / 32768f;
				}
				AudioClip val = AudioClip.Create(Path.GetFileNameWithoutExtension(path), num9 / num, num, num2, false);
				val.SetData(array2, 0);
				return val;
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[Рог Хеймдалля] Не удалось загрузить " + Path.GetFileName(path) + ": " + ex.Message));
				return null;
			}
		}
	}
}