Decompiled source of FalseSonMod v1.1.0

FalseSonMod.dll

Decompiled 11 hours ago
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using EntityStates;
using EntityStates.FalseSon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using R2API;
using RoR2;
using UnityEngine;

[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("FalseSonMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("FalseSonMod")]
[assembly: AssemblyTitle("FalseSonMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[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 FalseSonMod
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.blue.falsesonmod", "False Son Buffs", "1.1.0")]
	public class FalseSonModPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.blue.falsesonmod";

		public const string PluginName = "False Son Buffs";

		public const string PluginVersion = "1.1.0";

		public static ConfigEntry<float> HealthMultiplier;

		public static ConfigEntry<float> DamageMultiplier;

		public static ConfigEntry<float> ArmorBonus;

		public static ConfigEntry<float> MoveSpeedMultiplier;

		public static ConfigEntry<float> RegenMultiplier;

		public static ConfigEntry<float> GuaranteedAttackSpeedMultiplier;

		public static ConfigEntry<float> GuaranteedArmorFromSpikes;

		public static ConfigEntry<float> GuaranteedRegenFromSpentSpikes;

		public static ConfigEntry<float> ExtraJumpPowerOnSpecial;

		public static ConfigEntry<float> ExtraJumpPowerDurationSeconds;

		public static ConfigEntry<float> ChargeSlamWindupSeconds;

		public static ConfigEntry<float> ChargeMoveSpeedCoefficient;

		public static ConfigEntry<float> FallDamageBonusPerMeter;

		public static ConfigEntry<float> FallSizeBonusPerMeter;

		private void Awake()
		{
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Expected O, but got Unknown
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			HealthMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Buffs", "HealthMultiplier", 1.2f, "Max health multiplier.");
			DamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Buffs", "DamageMultiplier", 1.25f, "Base damage multiplier.");
			ArmorBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Buffs", "ArmorBonus", 15f, "Flat armor added to his base 20.");
			MoveSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Buffs", "MoveSpeedMultiplier", 1.1f, "Move speed multiplier.");
			RegenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Buffs", "RegenMultiplier", 1.5f, "HP regen multiplier.");
			GuaranteedAttackSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("LunarTampering", "GuaranteedAttackSpeedMultiplier", 1.15f, "Unconditional attack speed bonus standing in for the 'held spike' buff.");
			GuaranteedArmorFromSpikes = ((BaseUnityPlugin)this).Config.Bind<float>("LunarTampering", "GuaranteedArmorFromSpikes", 10f, "Unconditional flat armor standing in for the 'held spike' buff.");
			GuaranteedRegenFromSpentSpikes = ((BaseUnityPlugin)this).Config.Bind<float>("LunarTampering", "GuaranteedRegenFromSpentSpikes", 0.75f, "Unconditional flat regen standing in for the 'spent spike' buff.");
			ExtraJumpPowerOnSpecial = ((BaseUnityPlugin)this).Config.Bind<float>("Mobility", "ExtraJumpPowerMultiplier", 1.5f, "Jump power multiplier while the buff from using Special is active.");
			ExtraJumpPowerDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Mobility", "ExtraJumpPowerDurationSeconds", 2f, "How long the extra jump power lasts after using Special.");
			ChargeSlamWindupSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("ChargedSlam", "WindupSeconds", 0.05f, "How long the Charged Slam hold takes before it fires. Near-zero, not literally 0, to avoid input-frame edge cases. Also shrinks the charge-up animation to match.");
			ChargeMoveSpeedCoefficient = ((BaseUnityPlugin)this).Config.Bind<float>("ChargedSlam", "MoveSpeedCoefficientWhileCharging", 1.4f, "Movement speed multiplier while charging the slam (vanilla slows you down here). 1.0 = normal walk speed, >1 = faster than walking, roughly sprint-equivalent.");
			FallDamageBonusPerMeter = ((BaseUnityPlugin)this).Config.Bind<float>("ChargedSlam", "FallDamageBonusPerMeter", 0.03f, "Extra damage multiplier per meter fallen since last touching ground (Headstompers-style). Uncapped.");
			FallSizeBonusPerMeter = ((BaseUnityPlugin)this).Config.Bind<float>("ChargedSlam", "FallSizeBonusPerMeter", 0.02f, "Extra size multiplier (blast radius/VFX/force) per meter fallen. Uncapped.");
			RecalculateStatsAPI.GetStatCoefficients += new StatHookEventHandler(ApplyStatBuffs);
			new Harmony("com.blue.falsesonmod").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"False Son Buffs v1.1.0 loaded.");
		}

		private static bool IsFalseSon(CharacterBody body)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)body == (Object)null || (int)body.bodyIndex < 0)
			{
				return false;
			}
			string bodyName = BodyCatalog.GetBodyName(body.bodyIndex);
			if (!string.IsNullOrEmpty(bodyName))
			{
				return bodyName.Contains("FalseSon");
			}
			return false;
		}

		private void ApplyStatBuffs(CharacterBody body, StatHookEventArgs args)
		{
			if (IsFalseSon(body))
			{
				args.healthMultAdd += HealthMultiplier.Value - 1f;
				args.damageMultAdd += DamageMultiplier.Value - 1f;
				args.armorAdd += ArmorBonus.Value;
				args.moveSpeedMultAdd += MoveSpeedMultiplier.Value - 1f;
				args.regenMultAdd += RegenMultiplier.Value - 1f;
				args.attackSpeedMultAdd += GuaranteedAttackSpeedMultiplier.Value - 1f;
				args.armorAdd += GuaranteedArmorFromSpikes.Value;
				args.baseRegenAdd += GuaranteedRegenFromSpentSpikes.Value;
			}
		}
	}
	[HarmonyPatch(typeof(ClubSwing3), "OnEnter")]
	public static class ClubSwing3ChargePatch
	{
		private static readonly Type StateType = typeof(ClubSwing3);

		private static readonly FieldInfo BaseChargeDurationField = AccessTools.Field(StateType, "baseChargeDuration");

		private static readonly FieldInfo WalkSpeedCoefficientField = AccessTools.Field(StateType, "walkSpeedCoefficient");

		private static void Prefix(ClubSwing3 __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody characterBody = ((EntityState)__instance).characterBody;
			if (!((Object)(object)characterBody == (Object)null))
			{
				string bodyName = BodyCatalog.GetBodyName(characterBody.bodyIndex);
				if (!string.IsNullOrEmpty(bodyName) && bodyName.Contains("FalseSon"))
				{
					BaseChargeDurationField?.SetValue(__instance, FalseSonModPlugin.ChargeSlamWindupSeconds.Value);
					WalkSpeedCoefficientField?.SetValue(__instance, FalseSonModPlugin.ChargeMoveSpeedCoefficient.Value);
					Debug.Log((object)("[FalseSonMod] ClubSwing3 (charge hold) tweaked: chargeDuration=" + $"{FalseSonModPlugin.ChargeSlamWindupSeconds.Value}, walkSpeedCoeff=" + $"{FalseSonModPlugin.ChargeMoveSpeedCoefficient.Value}"));
				}
			}
		}
	}
	[HarmonyPatch(typeof(ChargedClubSwing), "OnEnter")]
	public static class ChargedClubSwingTweaksPatch
	{
		private static readonly Type StateType = typeof(ChargedClubSwing);

		private static readonly FieldInfo BaseDurationField = AccessTools.Field(StateType, "baseDuration");

		private static readonly FieldInfo BaseMinimumDurationField = AccessTools.Field(StateType, "baseMinimumDuration");

		private static readonly FieldInfo PlayerWalkSpeedCoefficientField = AccessTools.Field(StateType, "playerWalkSpeedCoefficient");

		private static readonly FieldInfo BlastRadiusField = AccessTools.Field(StateType, "blastRadius");

		private static readonly FieldInfo BlastVfxScaleField = AccessTools.Field(StateType, "blastVFXScaleMultiplier");

		private static readonly FieldInfo BlastDamageCoefficientField = AccessTools.Field(StateType, "blastDamageCoefficient");

		private static readonly FieldInfo BlastForceField = AccessTools.Field(StateType, "blastForce");

		private static void Prefix(ChargedClubSwing __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody characterBody = ((EntityState)__instance).characterBody;
			if ((Object)(object)characterBody == (Object)null)
			{
				return;
			}
			string bodyName = BodyCatalog.GetBodyName(characterBody.bodyIndex);
			if (!string.IsNullOrEmpty(bodyName) && bodyName.Contains("FalseSon"))
			{
				float value = FalseSonModPlugin.ChargeSlamWindupSeconds.Value;
				BaseDurationField?.SetValue(__instance, value);
				BaseMinimumDurationField?.SetValue(__instance, value);
				PlayerWalkSpeedCoefficientField?.SetValue(__instance, FalseSonModPlugin.ChargeMoveSpeedCoefficient.Value);
				FallHeightTracker fallHeightTracker = ((Component)characterBody).GetComponent<FallHeightTracker>();
				if ((Object)(object)fallHeightTracker == (Object)null)
				{
					fallHeightTracker = ((Component)characterBody).gameObject.AddComponent<FallHeightTracker>();
				}
				float currentFallDistance = fallHeightTracker.CurrentFallDistance;
				float num = currentFallDistance * FalseSonModPlugin.FallDamageBonusPerMeter.Value;
				float num2 = currentFallDistance * FalseSonModPlugin.FallSizeBonusPerMeter.Value;
				if (BlastRadiusField != null)
				{
					BlastRadiusField.SetValue(__instance, (float)BlastRadiusField.GetValue(__instance) * (1f + num2));
				}
				if (BlastVfxScaleField != null)
				{
					BlastVfxScaleField.SetValue(__instance, (float)BlastVfxScaleField.GetValue(__instance) * (1f + num2));
				}
				if (BlastForceField != null)
				{
					BlastForceField.SetValue(__instance, (float)BlastForceField.GetValue(__instance) * (1f + num2));
				}
				if (BlastDamageCoefficientField != null)
				{
					BlastDamageCoefficientField.SetValue(__instance, (float)BlastDamageCoefficientField.GetValue(__instance) * (1f + num));
				}
				Debug.Log((object)($"[FalseSonMod] ChargedClubSwing (impact) tweaked: fallDistance={currentFallDistance:F1}, " + $"damageBonus={num:F2}, sizeBonus={num2:F2}"));
			}
		}
	}
	[HarmonyPatch(typeof(GenericSkill), "OnExecute")]
	public static class SpecialJumpBoostPatch
	{
		private static void Postfix(GenericSkill __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody characterBody = __instance.characterBody;
			if ((Object)(object)characterBody == (Object)null)
			{
				return;
			}
			string bodyName = BodyCatalog.GetBodyName(characterBody.bodyIndex);
			if (string.IsNullOrEmpty(bodyName) || !bodyName.Contains("FalseSon"))
			{
				return;
			}
			SkillLocator component = ((Component)characterBody).GetComponent<SkillLocator>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)__instance != (Object)(object)component.special))
			{
				TemporaryJumpPowerBoost temporaryJumpPowerBoost = ((Component)characterBody).GetComponent<TemporaryJumpPowerBoost>();
				if ((Object)(object)temporaryJumpPowerBoost == (Object)null)
				{
					temporaryJumpPowerBoost = ((Component)characterBody).gameObject.AddComponent<TemporaryJumpPowerBoost>();
				}
				temporaryJumpPowerBoost.Refresh(FalseSonModPlugin.ExtraJumpPowerOnSpecial.Value, FalseSonModPlugin.ExtraJumpPowerDurationSeconds.Value);
			}
		}
	}
	public class TemporaryJumpPowerBoost : MonoBehaviour
	{
		private static MemberInfo _cachedMember;

		private static object _cachedTarget;

		private static bool _searched;

		private CharacterMotor _motor;

		private CharacterBody _body;

		private float _baseValue;

		private float _timer;

		private void Awake()
		{
			_motor = ((Component)this).GetComponent<CharacterMotor>();
			_body = ((Component)this).GetComponent<CharacterBody>();
		}

		private static MemberInfo FindJumpPowerMember(out bool onMotor)
		{
			onMotor = true;
			Type[] array = new Type[2]
			{
				typeof(CharacterMotor),
				typeof(CharacterBody)
			};
			foreach (Type type in array)
			{
				MemberInfo memberInfo = (from m in type.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where m is FieldInfo || m is PropertyInfo
					where m.Name.ToLowerInvariant().Contains("jump") && m.Name.ToLowerInvariant().Contains("power")
					select m).FirstOrDefault();
				if (memberInfo != null)
				{
					onMotor = type == typeof(CharacterMotor);
					return memberInfo;
				}
			}
			return null;
		}

		private float GetValue(object target, MemberInfo member)
		{
			if (!(member is FieldInfo fieldInfo))
			{
				return (float)((PropertyInfo)member).GetValue(target);
			}
			return (float)fieldInfo.GetValue(target);
		}

		private void SetValue(object target, MemberInfo member, float value)
		{
			if (member is FieldInfo fieldInfo)
			{
				fieldInfo.SetValue(target, value);
			}
			else
			{
				((PropertyInfo)member).SetValue(target, value);
			}
		}

		public void Refresh(float multiplier, float duration)
		{
			if (!_searched)
			{
				_cachedMember = FindJumpPowerMember(out var onMotor);
				_cachedTarget = (onMotor ? ((object)_motor) : ((object)_body));
				_searched = true;
				if (_cachedMember == null)
				{
					Debug.LogWarning((object)"[FalseSonMod] Could not find a jump-power member on CharacterMotor or CharacterBody. Jump boost on Special is disabled. Report this so the field name can be found another way.");
				}
				else
				{
					Debug.Log((object)("[FalseSonMod] Using jump-power member: " + _cachedMember.DeclaringType.Name + "." + _cachedMember.Name));
				}
			}
			if (_cachedMember == null)
			{
				return;
			}
			object obj = ((_cachedMember.DeclaringType == typeof(CharacterMotor)) ? ((object)_motor) : ((object)_body));
			if (obj != null)
			{
				if (_timer <= 0f)
				{
					_baseValue = GetValue(obj, _cachedMember);
				}
				_timer = duration;
				SetValue(obj, _cachedMember, _baseValue * multiplier);
			}
		}

		private void Update()
		{
			if (_timer <= 0f || _cachedMember == null)
			{
				return;
			}
			_timer -= Time.deltaTime;
			if (_timer <= 0f)
			{
				object obj = ((_cachedMember.DeclaringType == typeof(CharacterMotor)) ? ((object)_motor) : ((object)_body));
				if (obj != null)
				{
					SetValue(obj, _cachedMember, _baseValue);
				}
			}
		}
	}
	[BepInPlugin("com.blue.falsesondiagnostics", "False Son Diagnostics", "1.0.0")]
	public class FalseSonDiagnosticsPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.blue.falsesondiagnostics";

		public const string PluginName = "False Son Diagnostics";

		public const string PluginVersion = "1.0.0";

		private bool _dumpedTypes;

		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"False Son Diagnostics loaded. F6 = type dump, F7 = live state dump.");
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)287) && !_dumpedTypes)
			{
				DumpFalseSonTypes();
				_dumpedTypes = true;
			}
			if (Input.GetKeyDown((KeyCode)288))
			{
				DumpLocalBodyCurrentStates();
			}
		}

		private void DumpFalseSonTypes()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"---- Scanning loaded assemblies for FalseSon-related EntityStates types ----");
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type[] types;
				try
				{
					types = assembly.GetTypes();
				}
				catch
				{
					continue;
				}
				foreach (Type item in types.Where((Type t) => t.Namespace != null && t.Namespace.Contains("EntityStates") && (t.Namespace.Contains("FalseSon") || t.Name.Contains("FalseSon") || t.Name.Contains("Slam") || t.Name.Contains("Charge"))))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("TYPE: " + item.FullName));
					FieldInfo[] fields = item.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("    field: " + fieldInfo.FieldType.Name + " " + fieldInfo.Name));
					}
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"---- Dump complete ----");
		}

		private void DumpLocalBodyCurrentStates()
		{
			CharacterBody val = PlayerCharacterMasterController.instances?.Select(delegate(PlayerCharacterMasterController p)
			{
				CharacterMaster master = p.master;
				return (master == null) ? null : master.GetBody();
			}).FirstOrDefault((Func<CharacterBody, bool>)((CharacterBody b) => (Object)(object)b != (Object)null && b.isPlayerControlled));
			if ((Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"No local player body found (are you in a run?).");
				return;
			}
			SkillLocator component = ((Component)val).GetComponent<SkillLocator>();
			if ((Object)(object)component == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"No SkillLocator on local body.");
				return;
			}
			LogSlot("Primary", component.primary);
			LogSlot("Secondary", component.secondary);
			LogSlot("Utility", component.utility);
			LogSlot("Special", component.special);
			void LogSlot(string slotName, GenericSkill skill)
			{
				EntityStateMachine val2 = (((Object)(object)skill != (Object)null) ? skill.stateMachine : null);
				string text = (((Object)(object)val2 != (Object)null && val2.state != null) ? ((object)val2.state).GetType().FullName : "(none)");
				((BaseUnityPlugin)this).Logger.LogInfo((object)(slotName + ": currentState = " + text));
			}
		}
	}
	public class FallHeightTracker : MonoBehaviour
	{
		private CharacterMotor _motor;

		private float _peakY;

		private bool _wasGrounded = true;

		public float CurrentFallDistance { get; private set; }

		private void Awake()
		{
			_motor = ((Component)this).GetComponent<CharacterMotor>();
		}

		private void FixedUpdate()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_motor == (Object)null)
			{
				return;
			}
			bool isGrounded = _motor.isGrounded;
			float y = ((Component)this).transform.position.y;
			if (!isGrounded)
			{
				if (_wasGrounded)
				{
					_peakY = y;
				}
				else
				{
					_peakY = Mathf.Max(_peakY, y);
				}
				CurrentFallDistance = Mathf.Max(0f, _peakY - y);
			}
			else if (!_wasGrounded)
			{
				CurrentFallDistance = Mathf.Max(0f, _peakY - y);
			}
			_wasGrounded = isGrounded;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "FalseSonMod";

		public const string PLUGIN_NAME = "FalseSonMod";

		public const string PLUGIN_VERSION = "1.1.0";
	}
}