Decompiled source of LoreAccurateLightningStrike v1.0.0

LoreAccurateLightningStrike.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.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 LoreAccurateLightningStrike
{
	[BepInPlugin("rook.valheim.loreaccuratelightningstrike", "Lore Accurate Lightning Strike", "1.0.0")]
	public sealed class LightningStrikePlugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Attack), "FireProjectileBurst")]
		private static class FireProjectileBurstPatch
		{
			private static void Prefix(Attack __instance)
			{
				if (_instance != null && _baselineReady && __instance != null && IsLightningStrikeAttack(__instance))
				{
					ApplyProjectileTuning(__instance);
					if (!_loggedLiveAttack)
					{
						_loggedLiveAttack = true;
						((BaseUnityPlugin)_instance).Logger.LogInfo((object)("Live Lightning Strike attack intercepted: velocity=" + __instance.m_projectileVelMin.ToString("0.##") + "-" + __instance.m_projectileVel.ToString("0.##") + ", accuracy=" + __instance.m_projectileAccuracy.ToString("0.##") + "."));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Projectile), "Setup")]
		private static class ProjectileSetupPatch
		{
			private static void Prefix(ref Vector3 velocity, ItemData item)
			{
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				if (_instance != null && _baselineReady && IsLightningStrikeItem(item))
				{
					float num = _baseMaxVelocity * Mathf.Max(0.01f, _instance._speedMultiplier.Value);
					if (((Vector3)(ref velocity)).sqrMagnitude > 0.0001f)
					{
						velocity = ((Vector3)(ref velocity)).normalized * num;
					}
					if (!_loggedProjectileSetup)
					{
						_loggedProjectileSetup = true;
						((BaseUnityPlugin)_instance).Logger.LogInfo((object)("Lightning Strike Projectile.Setup intercepted: final speed=" + ((Vector3)(ref velocity)).magnitude.ToString("0.##") + "."));
					}
				}
			}
		}

		public const string PluginGuid = "rook.valheim.loreaccuratelightningstrike";

		public const string PluginName = "Lore Accurate Lightning Strike";

		public const string PluginVersion = "1.0.0";

		private static LightningStrikePlugin _instance;

		private static bool _baselineReady;

		private static float _baseMinVelocity;

		private static float _baseMaxVelocity;

		private static GameObject _lightningStrikeProjectile;

		private static bool _loggedLiveAttack;

		private static bool _loggedProjectileSetup;

		private ConfigEntry<string> _prefabName;

		private ConfigEntry<string> _itemName;

		private ConfigEntry<float> _speedMultiplier;

		private ConfigEntry<float> _scatterDegrees;

		private ConfigEntry<bool> _disableCircularScatter;

		private ConfigEntry<bool> _removeLaunchArc;

		private IEnumerator Start()
		{
			_instance = this;
			new Harmony("rook.valheim.loreaccuratelightningstrike").PatchAll();
			_prefabName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PrefabName", "StaffThunderBlood", "Internal prefab name for Lightning Strike in Valheim 1.0.");
			if (string.Equals(_prefabName.Value, "StaffLightning", StringComparison.OrdinalIgnoreCase))
			{
				_prefabName.Value = "StaffThunderBlood";
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Migrated obsolete PrefabName StaffLightning to StaffThunderBlood.");
			}
			_itemName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ItemName", "Lightning Strike", "Displayed item name, raw localization key, or prefab name to patch.");
			_speedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Projectile", "SpeedMultiplier", 3f, "Multiplier applied to both minimum and maximum projectile velocity.");
			_scatterDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("Projectile", "ScatterDegrees", 0f, "Projectile spread in degrees. Zero removes normal random scatter.");
			_disableCircularScatter = ((BaseUnityPlugin)this).Config.Bind<bool>("Projectile", "DisableCircularScatter", true, "Also disables circular distribution of multi-projectile attacks.");
			_removeLaunchArc = ((BaseUnityPlugin)this).Config.Bind<bool>("Projectile", "RemoveLaunchArc", true, "Removes Lightning Strike's built-in upward launch angle so faster bolts track the crosshair.");
			while ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items == null)
			{
				yield return null;
			}
			PatchItem();
		}

		private void PatchItem()
		{
			string text = (_prefabName.Value ?? "StaffThunderBlood").Trim();
			GameObject val = ObjectDB.instance.GetItemPrefab(text);
			string text2 = (_itemName.Value ?? "Lightning Strike").Trim();
			if ((Object)(object)val != (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Located Lightning Strike using prefab '" + text + "'."));
			}
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null)
				{
					string text3 = component.m_itemData.m_shared.m_name ?? string.Empty;
					if (Matches(((Object)item).name, text2) || Matches(text3, text2))
					{
						val = item;
						((BaseUnityPlugin)this).Logger.LogInfo((object)("Matched item: prefab='" + ((Object)item).name + "', key='" + text3 + "'."));
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not find prefab '" + text + "' or an ObjectDB item matching '" + text2 + "'."));
				return;
			}
			Attack attack = val.GetComponent<ItemDrop>().m_itemData.m_shared.m_attack;
			if (attack == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Matched item has no primary attack data.");
				return;
			}
			_baseMinVelocity = attack.m_projectileVelMin;
			_baseMaxVelocity = attack.m_projectileVel;
			_lightningStrikeProjectile = attack.m_attackProjectile;
			_baselineReady = true;
			float baseMinVelocity = _baseMinVelocity;
			float baseMaxVelocity = _baseMaxVelocity;
			ApplyProjectileTuning(attack);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Lightning Strike patched: velocity " + baseMinVelocity.ToString("0.##") + "-" + baseMaxVelocity.ToString("0.##") + " -> " + attack.m_projectileVelMin.ToString("0.##") + "-" + attack.m_projectileVel.ToString("0.##") + "; scatter=" + Mathf.Max(0f, _scatterDegrees.Value).ToString("0.##") + " degrees. Runtime firing patch active."));
		}

		private static void ApplyProjectileTuning(Attack attack)
		{
			if (_instance != null && _baselineReady && attack != null)
			{
				float num = Mathf.Max(0.01f, _instance._speedMultiplier.Value);
				float num2 = Mathf.Max(0f, _instance._scatterDegrees.Value);
				attack.m_projectileVelMin = _baseMinVelocity * num;
				attack.m_projectileVel = _baseMaxVelocity * num;
				attack.m_projectileAccuracyMin = num2;
				attack.m_projectileAccuracy = num2;
				attack.m_randomVelocity = false;
				if (_instance._removeLaunchArc.Value)
				{
					attack.m_launchAngle = 0f;
				}
				if (_instance._disableCircularScatter.Value)
				{
					attack.m_circularProjectileLaunch = false;
					attack.m_distributeProjectilesAroundCircle = false;
				}
			}
		}

		private static bool IsLightningStrikeAttack(Attack attack)
		{
			if (attack == null)
			{
				return false;
			}
			if ((Object)(object)_lightningStrikeProjectile != (Object)null && (Object)(object)attack.m_attackProjectile == (Object)(object)_lightningStrikeProjectile)
			{
				return true;
			}
			return IsLightningStrikeItem(attack.GetWeapon());
		}

		private static bool IsLightningStrikeItem(ItemData item)
		{
			if (_instance == null || item == null)
			{
				return false;
			}
			string b = (_instance._prefabName.Value ?? "StaffThunderBlood").Trim();
			if ((Object)(object)item.m_dropPrefab != (Object)null && string.Equals(((Object)item.m_dropPrefab).name, b, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			string candidate = ((item.m_shared != null) ? item.m_shared.m_name : string.Empty);
			if (!Matches(candidate, "Lightning Strike") && !Matches(candidate, "StaffThunderBlood"))
			{
				return Matches(candidate, "staff_thunderblood");
			}
			return true;
		}

		private static bool Matches(string candidate, string wanted)
		{
			if (string.IsNullOrEmpty(candidate) || string.IsNullOrEmpty(wanted))
			{
				return false;
			}
			if (candidate.IndexOf(wanted, StringComparison.OrdinalIgnoreCase) < 0)
			{
				return candidate.Replace("$", string.Empty).Replace("_", string.Empty).IndexOf(wanted.Replace(" ", string.Empty), StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}
	}
}