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 HealthMultiplier; public static ConfigEntry DamageMultiplier; public static ConfigEntry ArmorBonus; public static ConfigEntry MoveSpeedMultiplier; public static ConfigEntry RegenMultiplier; public static ConfigEntry GuaranteedAttackSpeedMultiplier; public static ConfigEntry GuaranteedArmorFromSpikes; public static ConfigEntry GuaranteedRegenFromSpentSpikes; public static ConfigEntry ExtraJumpPowerOnSpecial; public static ConfigEntry ExtraJumpPowerDurationSeconds; public static ConfigEntry ChargeSlamWindupSeconds; public static ConfigEntry ChargeMoveSpeedCoefficient; public static ConfigEntry FallDamageBonusPerMeter; public static ConfigEntry 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("Buffs", "HealthMultiplier", 1.2f, "Max health multiplier."); DamageMultiplier = ((BaseUnityPlugin)this).Config.Bind("Buffs", "DamageMultiplier", 1.25f, "Base damage multiplier."); ArmorBonus = ((BaseUnityPlugin)this).Config.Bind("Buffs", "ArmorBonus", 15f, "Flat armor added to his base 20."); MoveSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Buffs", "MoveSpeedMultiplier", 1.1f, "Move speed multiplier."); RegenMultiplier = ((BaseUnityPlugin)this).Config.Bind("Buffs", "RegenMultiplier", 1.5f, "HP regen multiplier."); GuaranteedAttackSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("LunarTampering", "GuaranteedAttackSpeedMultiplier", 1.15f, "Unconditional attack speed bonus standing in for the 'held spike' buff."); GuaranteedArmorFromSpikes = ((BaseUnityPlugin)this).Config.Bind("LunarTampering", "GuaranteedArmorFromSpikes", 10f, "Unconditional flat armor standing in for the 'held spike' buff."); GuaranteedRegenFromSpentSpikes = ((BaseUnityPlugin)this).Config.Bind("LunarTampering", "GuaranteedRegenFromSpentSpikes", 0.75f, "Unconditional flat regen standing in for the 'spent spike' buff."); ExtraJumpPowerOnSpecial = ((BaseUnityPlugin)this).Config.Bind("Mobility", "ExtraJumpPowerMultiplier", 1.5f, "Jump power multiplier while the buff from using Special is active."); ExtraJumpPowerDurationSeconds = ((BaseUnityPlugin)this).Config.Bind("Mobility", "ExtraJumpPowerDurationSeconds", 2f, "How long the extra jump power lasts after using Special."); ChargeSlamWindupSeconds = ((BaseUnityPlugin)this).Config.Bind("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("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("ChargedSlam", "FallDamageBonusPerMeter", 0.03f, "Extra damage multiplier per meter fallen since last touching ground (Headstompers-style). Uncapped."); FallSizeBonusPerMeter = ((BaseUnityPlugin)this).Config.Bind("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(); if ((Object)(object)fallHeightTracker == (Object)null) { fallHeightTracker = ((Component)characterBody).gameObject.AddComponent(); } 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(); if (!((Object)(object)component == (Object)null) && !((Object)(object)__instance != (Object)(object)component.special)) { TemporaryJumpPowerBoost temporaryJumpPowerBoost = ((Component)characterBody).GetComponent(); if ((Object)(object)temporaryJumpPowerBoost == (Object)null) { temporaryJumpPowerBoost = ((Component)characterBody).gameObject.AddComponent(); } 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(); _body = ((Component)this).GetComponent(); } 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 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(); 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(); } 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"; } }