Some mods may be broken due to the recent Alloyed Collective update.
Decompiled source of R2API RecalculateStats v1.6.5
plugins/R2API.RecalculateStats/R2API.RecalculateStats.dll
Decompiled 2 weeks agousing System; using System.ComponentModel; 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.Logging; using IL.RoR2; using Microsoft.CodeAnalysis; using Mono.Cecil.Cil; using MonoMod.Cil; using On.RoR2; using R2API.AutoVersionGen; using R2API.Utils; using RoR2; using RoR2BepInExPack.Utilities; 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("R2API.RecalculateStats")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.6.5.0")] [assembly: AssemblyInformationalVersion("1.6.5+59e000a0da6e3270eff656cbd2028bee36b7399f")] [assembly: AssemblyProduct("R2API.RecalculateStats")] [assembly: AssemblyTitle("R2API.RecalculateStats")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.6.5.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } } namespace R2API { [AutoVersion] public static class RecalculateStatsAPI { public class CustomStats { public bool barrierDecayFrozen; public float barrierDecayRateAdd; public float barrierDecayRateMult = 1f; public float luckFromBody; internal void ResetStats() { barrierDecayFrozen = false; barrierDecayRateAdd = 0f; barrierDecayRateMult = 1f; luckFromBody = 0f; } } public class StatHookEventArgs : EventArgs { [EditorBrowsable(EditorBrowsableState.Never)] public const string _levelMultiplier = "Used for internal documentation"; public float baseHealthAdd; public float levelHealthAdd; public float healthMultAdd; public float healthTotalMult = 1f; public float baseShieldAdd; public float levelShieldAdd; public float shieldMultAdd; public float shieldTotalMult = 1f; public float baseRegenAdd; public float levelRegenAdd; public float regenMultAdd; public float regenTotalMult = 1f; public float baseMoveSpeedAdd; public float levelMoveSpeedAdd; public float moveSpeedMultAdd; public float moveSpeedTotalMult = 1f; public float moveSpeedReductionMultAdd; public float sprintSpeedAdd; public int moveSpeedRootCount; public float baseJumpPowerAdd; public float levelJumpPowerAdd; public float jumpPowerMultAdd; public float jumpPowerTotalMult = 1f; public float baseDamageAdd; public float levelDamageAdd; public float damageMultAdd; public float damageTotalMult = 1f; public float baseAttackSpeedAdd; public float levelAttackSpeedAdd; public float attackSpeedMultAdd; public float attackSpeedTotalMult = 1f; public float attackSpeedReductionMultAdd; public float critAdd; public float levelCritAdd; public float critTotalMult = 1f; public float critDamageMultAdd; public float critDamageTotalMult = 1f; public float bleedChanceAdd; public float bleedChanceMult = 1f; public float armorAdd; public float levelArmorAdd; public float armorTotalMult = 1f; public float baseCurseAdd; public float curseTotalMult = 1f; public SkillSlotStatModifiers allSkills = new SkillSlotStatModifiers(); public SkillSlotStatModifiers primarySkill = new SkillSlotStatModifiers(); public SkillSlotStatModifiers secondarySkill = new SkillSlotStatModifiers(); public SkillSlotStatModifiers utilitySkill = new SkillSlotStatModifiers(); public SkillSlotStatModifiers specialSkill = new SkillSlotStatModifiers(); [Obsolete("Use StatEventHookArgs.allSkills.cooldownFlatReduction instead")] [EditorBrowsable(EditorBrowsableState.Never)] public float cooldownReductionAdd; [Obsolete("Use StatEventHookArgs.allSkills.cooldownMultAdd instead")] [EditorBrowsable(EditorBrowsableState.Never)] public float cooldownMultAdd; [Obsolete("Use StatEventHookArgs.primarySkill.cooldownMultAdd instead")] [EditorBrowsable(EditorBrowsableState.Never)] public float primaryCooldownMultAdd; [Obsolete("Use StatEventHookArgs.secondarySkill.cooldownMultAdd instead")] [EditorBrowsable(EditorBrowsableState.Never)] public float secondaryCooldownMultAdd; [Obsolete("Use StatEventHookArgs.utilitySkill.cooldownMultAdd instead")] [EditorBrowsable(EditorBrowsableState.Never)] public float utilityCooldownMultAdd; [Obsolete("Use StatEventHookArgs.specialSkill.cooldownMultAdd instead")] [EditorBrowsable(EditorBrowsableState.Never)] public float specialCooldownMultAdd; public float levelFlatAdd; public float levelMultAdd; public bool shouldFreezeBarrier; public float barrierDecayMult = 1f; public float barrierDecayAdd; public float luckAdd; public int jumpCountAdd; public int jumpCountMult = 1; internal float CalculateFinalSkillCooldownScale(SkillSlot slot) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected I4, but got Unknown float multiplierAdd = 0f; float reductionMultiplier = 0f; float totalMultiplier = 1f; applyModifiers(in allSkills); multiplierAdd += Math.Max(0f, cooldownMultAdd); switch ((int)slot) { case 0: applyModifiers(in primarySkill); multiplierAdd += Math.Max(0f, primaryCooldownMultAdd); break; case 1: applyModifiers(in secondarySkill); multiplierAdd += Math.Max(0f, secondaryCooldownMultAdd); break; case 2: applyModifiers(in utilitySkill); multiplierAdd += Math.Max(0f, utilityCooldownMultAdd); break; case 3: applyModifiers(in specialSkill); multiplierAdd += Math.Max(0f, specialCooldownMultAdd); break; } return (1f + multiplierAdd) / (1f + reductionMultiplier) * totalMultiplier; void applyModifiers(in SkillSlotStatModifiers statModifiers) { multiplierAdd += Math.Max(0f, statModifiers.cooldownMultAdd); reductionMultiplier += Math.Max(0f, statModifiers.cooldownReductionMultAdd); totalMultiplier *= Math.Max(0f, statModifiers.cooldownMultiplier); } } internal float CalculateSkillCooldownFlatReduction(SkillSlot slot) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected I4, but got Unknown float flatReduction = 0f; flatReduction += Math.Max(0f, cooldownReductionAdd); applyModifiers(in allSkills); switch ((int)slot) { case 0: applyModifiers(in primarySkill); break; case 1: applyModifiers(in secondarySkill); break; case 2: applyModifiers(in utilitySkill); break; case 3: applyModifiers(in specialSkill); break; } return flatReduction; void applyModifiers(in SkillSlotStatModifiers statModifiers) { flatReduction += Math.Max(0f, statModifiers.cooldownFlatReduction); } } internal int CalculateSkillBonusStocks(SkillSlot slot) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected I4, but got Unknown int bonusStockAdd = 0; applyModifiers(in allSkills); switch ((int)slot) { case 0: applyModifiers(in primarySkill); break; case 1: applyModifiers(in secondarySkill); break; case 2: applyModifiers(in utilitySkill); break; case 3: applyModifiers(in specialSkill); break; } return bonusStockAdd; void applyModifiers(in SkillSlotStatModifiers statModifiers) { bonusStockAdd += Math.Max(0, statModifiers.bonusStockAdd); } } } public struct SkillSlotStatModifiers { public float cooldownMultAdd; public float cooldownReductionMultAdd; public float cooldownFlatReduction; public float cooldownMultiplier; public int bonusStockAdd; public SkillSlotStatModifiers() { cooldownMultAdd = 0f; cooldownReductionMultAdd = 0f; cooldownFlatReduction = 0f; cooldownMultiplier = 1f; bonusStockAdd = 0; } } public delegate void StatHookEventHandler(CharacterBody sender, StatHookEventArgs args); [CompilerGenerated] private static class <>O { public static Manipulator <0>__HookRecalculateStats; public static hook_CheckRoll_float_float_CharacterMaster <1>__RoundLuckInCheckRoll; public static Manipulator <2>__ModifyBarrierDecayRate; public static Action<CharacterBody> <3>__GetStatMods; public static Action<CharacterBody> <4>__applyPrimarySkillStatModifiers; public static Action<CharacterBody> <5>__applySecondarySkillStatModifiers; public static Action<CharacterBody> <6>__applyUtilitySkillStatModifiers; public static Action<CharacterBody> <7>__applySpecialSkillStatModifiers; } public const string PluginGUID = "com.bepis.r2api.recalculatestats"; public const string PluginName = "R2API.RecalculateStats"; private static bool _hooksEnabled = false; private static StatHookEventArgs StatMods; private static CustomStats BodyCustomStats; private static FixedConditionalWeakTable<CharacterBody, CustomStats> characterCustomStats = new FixedConditionalWeakTable<CharacterBody, CustomStats>(); public const string PluginVersion = "1.6.5"; [Obsolete("All submodules are automatically loaded and this property is now unused")] public static bool Loaded => true; private static event StatHookEventHandler _getStatCoefficients; public static event StatHookEventHandler GetStatCoefficients { add { SetHooks(); _getStatCoefficients += value; } remove { _getStatCoefficients -= value; if (RecalculateStatsAPI._getStatCoefficients != null) { Delegate[] invocationList = RecalculateStatsAPI._getStatCoefficients.GetInvocationList(); if (invocationList == null || invocationList.Length != 0) { return; } } UnsetHooks(); } } internal static void SetHooks() { //IL_0018: 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_0023: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown if (!_hooksEnabled) { object obj = <>O.<0>__HookRecalculateStats; if (obj == null) { Manipulator val = HookRecalculateStats; <>O.<0>__HookRecalculateStats = val; obj = (object)val; } CharacterBody.RecalculateStats += (Manipulator)obj; object obj2 = <>O.<1>__RoundLuckInCheckRoll; if (obj2 == null) { hook_CheckRoll_float_float_CharacterMaster val2 = RoundLuckInCheckRoll; <>O.<1>__RoundLuckInCheckRoll = val2; obj2 = (object)val2; } Util.CheckRoll_float_float_CharacterMaster += (hook_CheckRoll_float_float_CharacterMaster)obj2; object obj3 = <>O.<2>__ModifyBarrierDecayRate; if (obj3 == null) { Manipulator val3 = ModifyBarrierDecayRate; <>O.<2>__ModifyBarrierDecayRate = val3; obj3 = (object)val3; } HealthComponent.ServerFixedUpdate += (Manipulator)obj3; _hooksEnabled = true; } } internal static void UnsetHooks() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0050: 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) //IL_005b: Expected O, but got Unknown object obj = <>O.<0>__HookRecalculateStats; if (obj == null) { Manipulator val = HookRecalculateStats; <>O.<0>__HookRecalculateStats = val; obj = (object)val; } CharacterBody.RecalculateStats -= (Manipulator)obj; object obj2 = <>O.<1>__RoundLuckInCheckRoll; if (obj2 == null) { hook_CheckRoll_float_float_CharacterMaster val2 = RoundLuckInCheckRoll; <>O.<1>__RoundLuckInCheckRoll = val2; obj2 = (object)val2; } Util.CheckRoll_float_float_CharacterMaster -= (hook_CheckRoll_float_float_CharacterMaster)obj2; object obj3 = <>O.<2>__ModifyBarrierDecayRate; if (obj3 == null) { Manipulator val3 = ModifyBarrierDecayRate; <>O.<2>__ModifyBarrierDecayRate = val3; obj3 = (object)val3; } HealthComponent.ServerFixedUpdate -= (Manipulator)obj3; _hooksEnabled = false; } private static void HookRecalculateStats(ILContext il) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) ILCursor c = new ILCursor(il); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Action<CharacterBody>>((Action<CharacterBody>)GetStatMods); FindLocLevelMultiplierIndex(c, out var locLevelMultiplierIndex); Action emitLevelMultiplier = ((locLevelMultiplierIndex >= 0) ? new Action(EmitLevelMultiplier) : new Action(EmitFallbackLevelMultiplier)); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Action<CharacterBody>>((Action<CharacterBody>)delegate(CharacterBody body) { SetCustomStats(body); }); ModifyHealthStat(c, emitLevelMultiplier); ModifyShieldStat(c, emitLevelMultiplier); ModifyHealthRegenStat(c, emitLevelMultiplier); ModifyMovementSpeedStat(c, emitLevelMultiplier); ModifyJumpPowerStat(c, emitLevelMultiplier); ModifyDamageStat(c, emitLevelMultiplier); ModifyAttackSpeedStat(c, emitLevelMultiplier); ModifyCritStat(c, emitLevelMultiplier); ModifyBleedStat(c); ModifyArmorStat(c, emitLevelMultiplier); ModifyCurseStat(c); ModifySkillSlots(c); ModifyLevelingStat(c); ModifyJumpCountStat(c); ModifyLuckStat(c); void EmitFallbackLevelMultiplier() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) c.Emit(OpCodes.Ldc_R4, 0f); } void EmitLevelMultiplier() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) c.Emit(OpCodes.Ldloc, locLevelMultiplierIndex); } static void SetCustomStats(CharacterBody body) { BodyCustomStats = GetCustomStatsFromBody(body); if (Object.op_Implicit((Object)(object)body.master)) { CharacterMaster master = body.master; master.luck -= BodyCustomStats.luckFromBody; } BodyCustomStats.ResetStats(); if (Object.op_Implicit((Object)(object)body.master)) { CharacterMaster master2 = body.master; master2.luck += StatMods.luckAdd; BodyCustomStats.luckFromBody = StatMods.luckAdd; } BodyCustomStats.barrierDecayFrozen = StatMods.shouldFreezeBarrier; BodyCustomStats.barrierDecayRateMult = StatMods.barrierDecayMult; if (BodyCustomStats.barrierDecayRateMult < 0f) { BodyCustomStats.barrierDecayRateMult = 0f; } BodyCustomStats.barrierDecayRateAdd = StatMods.barrierDecayAdd; } } private static void GetStatMods(CharacterBody characterBody) { StatMods = new StatHookEventArgs(); if (RecalculateStatsAPI._getStatCoefficients == null) { return; } Delegate[] invocationList = RecalculateStatsAPI._getStatCoefficients.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { StatHookEventHandler statHookEventHandler = (StatHookEventHandler)invocationList[i]; try { statHookEventHandler(characterBody, StatMods); } catch (Exception arg) { RecalculateStatsPlugin.Logger.LogError((object)$"Exception thrown by : {statHookEventHandler.Method.DeclaringType.Name}.{statHookEventHandler.Method.Name}:\n{arg}"); } } } private static void FindLocLevelMultiplierIndex(ILCursor c, out int locLevelMultiplierIndex) { c.Index = 0; int _locLevelMultiplierIndex = -1; c.TryGotoNext(new Func<Instruction, bool>[4] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertyGetter(typeof(CharacterBody), "level")), (Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, 1f), (Instruction x) => ILPatternMatchingExt.MatchSub(x), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref _locLevelMultiplierIndex) }); locLevelMultiplierIndex = _locLevelMultiplierIndex; if (locLevelMultiplierIndex < 0) { RecalculateStatsPlugin.Logger.LogError((object)"FindLocLevelMultiplierIndex failed! Level-scaled stats will be ignored!"); } } private static void ModifyCurseStat(ILCursor c) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; if (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, 10f), (Instruction x) => ILPatternMatchingExt.MatchMul(x), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "cursePenalty")) })) { c.MoveAfterLabels(); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Action<CharacterBody>>((Action<CharacterBody>)delegate(CharacterBody body) { body.cursePenalty += StatMods.baseCurseAdd; body.cursePenalty *= StatMods.curseTotalMult; }); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyCurseStat failed."); } } private static void ModifySkillSlots(ILCursor c) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) MethodInfo unityObjectImplicitNullCheckMethod = typeof(Object).GetMethods(BindingFlags.Static | BindingFlags.Public).SingleOrDefault((MethodInfo m) => m.Name == "op_Implicit" && m.ReturnType == typeof(bool) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Object)); if (unityObjectImplicitNullCheckMethod == null) { RecalculateStatsPlugin.Logger.LogError((object)"ModifySkillSlots: Failed to find unity object implicit bool conversion method"); return; } c.Index = 0; ILLabel afterPrimarySkillBlockLabel = null; if (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<SkillLocator>(x, "primary"), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)unityObjectImplicitNullCheckMethod), (Instruction x) => ILPatternMatchingExt.MatchBrfalse(x, ref afterPrimarySkillBlockLabel) })) { c.Goto(afterPrimarySkillBlockLabel.Target, (MoveType)0, false); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Action<CharacterBody>>((Action<CharacterBody>)applyPrimarySkillStatModifiers); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifySkillSlots failed to find primary skill patch location."); } c.Index = 0; ILLabel afterSecondarySkillBlockLabel = null; if (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<SkillLocator>(x, "get_secondaryBonusStockSkill"), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)unityObjectImplicitNullCheckMethod), (Instruction x) => ILPatternMatchingExt.MatchBrfalse(x, ref afterSecondarySkillBlockLabel) })) { c.Goto(afterSecondarySkillBlockLabel.Target, (MoveType)0, false); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Action<CharacterBody>>((Action<CharacterBody>)applySecondarySkillStatModifiers); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifySkillSlots failed to find secondary skill patch location."); } c.Index = 0; ILLabel afterUtilitySkillBlockLabel = null; if (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<SkillLocator>(x, "get_utilityBonusStockSkill"), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)unityObjectImplicitNullCheckMethod), (Instruction x) => ILPatternMatchingExt.MatchBrfalse(x, ref afterUtilitySkillBlockLabel) })) { c.Goto(afterUtilitySkillBlockLabel.Target, (MoveType)0, false); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Action<CharacterBody>>((Action<CharacterBody>)applyUtilitySkillStatModifiers); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifySkillSlots failed to find utility skill patch location."); } c.Index = 0; ILLabel afterSpecialSkillBlockLabel = null; if (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<SkillLocator>(x, "get_specialBonusStockSkill"), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)unityObjectImplicitNullCheckMethod), (Instruction x) => ILPatternMatchingExt.MatchBrfalse(x, ref afterSpecialSkillBlockLabel) })) { c.Goto(afterSpecialSkillBlockLabel.Target, (MoveType)0, false); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Action<CharacterBody>>((Action<CharacterBody>)applySpecialSkillStatModifiers); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifySkillSlots failed to find special skill patch location."); } static void applyPrimarySkillStatModifiers(CharacterBody body) { applySkillSlotStatModifiers(body.skillLocator.primary, (SkillSlot)0); } static void applySecondarySkillStatModifiers(CharacterBody body) { applySkillSlotStatModifiers(body.skillLocator.secondaryBonusStockSkill, (SkillSlot)1); } static void applySkillSlotStatModifiers(GenericSkill genericSkill, SkillSlot skillSlot) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) genericSkill.cooldownScale *= StatMods.CalculateFinalSkillCooldownScale(skillSlot); genericSkill.flatCooldownReduction += StatMods.CalculateSkillCooldownFlatReduction(skillSlot); int num = StatMods.CalculateSkillBonusStocks(skillSlot); if ((int)skillSlot != 0) { num += genericSkill.bonusStockFromBody; } genericSkill.SetBonusStockFromBody(num); } static void applySpecialSkillStatModifiers(CharacterBody body) { applySkillSlotStatModifiers(body.skillLocator.specialBonusStockSkill, (SkillSlot)3); } static void applyUtilitySkillStatModifiers(CharacterBody body) { applySkillSlotStatModifiers(body.skillLocator.utilityBonusStockSkill, (SkillSlot)2); } } private static void ModifyLevelingStat(ILCursor c) { c.Index = 0; if (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertyGetter(typeof(CharacterBody), "level")), (Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, 1f), (Instruction x) => ILPatternMatchingExt.MatchSub(x) })) { c.EmitDelegate<Func<float, float>>((Func<float, float>)((float oldScaling) => (oldScaling + StatMods.levelFlatAdd) * (1f + StatMods.levelMultAdd))); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyLevelingStat failed."); } } private static void ModifyArmorStat(ILCursor c, Action emitLevelMultiplier) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; if (c.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseArmor") }) && c.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "armor")) })) { emitLevelMultiplier(); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float levelMultiplier) => StatMods.armorAdd + StatMods.levelArmorAdd * levelMultiplier)); c.Emit(OpCodes.Add); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdsfld(x, typeof(Buffs), "PermanentDebuff") }); c.GotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "armor")) }); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Action<CharacterBody>>((Action<CharacterBody>)delegate(CharacterBody body) { body.armor *= StatMods.armorTotalMult; }); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyArmorStat failed."); } } private static void ModifyAttackSpeedStat(ILCursor c, Action emitLevelMultiplier) { //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; int locBaseAttackSpeedIndex = -1; int locAttackSpeedMultIndex = -1; if (c.TryGotoNext(new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseAttackSpeed"), (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0), (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "levelAttackSpeed") }) && c.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref locBaseAttackSpeedIndex) }) && c.TryGotoNext(new Func<Instruction, bool>[4] { (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, locBaseAttackSpeedIndex), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locAttackSpeedMultIndex), (Instruction x) => ILPatternMatchingExt.MatchMul(x), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locBaseAttackSpeedIndex) })) { c.GotoPrev(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseAttackSpeed") }); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locBaseAttackSpeedIndex) }); emitLevelMultiplier(); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float levelMultiplier) => StatMods.baseAttackSpeedAdd + StatMods.levelAttackSpeedAdd * levelMultiplier)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.attackSpeedTotalMult)); c.Emit(OpCodes.Mul); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locAttackSpeedMultIndex) }); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.attackSpeedMultAdd)); c.Emit(OpCodes.Add); c.GotoNext(new Func<Instruction, bool>[2] { (Instruction x) => ILPatternMatchingExt.MatchDiv(x), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locAttackSpeedMultIndex) }); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float origSpeedReductionMult) => Mathf.Max(Mathf.Epsilon, origSpeedReductionMult + StatMods.attackSpeedReductionMultAdd))); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyAttackSpeedStat failed."); } } private static void ModifyCritStat(ILCursor c, Action emitLevelMultiplier) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_013e: 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) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; int locOrigCrit = -1; if (c.TryGotoNext(new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locOrigCrit), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "crit")) }) && c.TryGotoPrev((MoveType)2, new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "critMultiplier")) })) { int index = c.Index; c.Index = index - 1; c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.critDamageMultAdd)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.critDamageTotalMult)); c.Emit(OpCodes.Mul); c.GotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locOrigCrit) }); c.Emit(OpCodes.Ldloc, locOrigCrit); emitLevelMultiplier(); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float levelMultiplier) => StatMods.critAdd + StatMods.levelCritAdd * levelMultiplier)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.critTotalMult)); c.Emit(OpCodes.Mul); c.Emit(OpCodes.Stloc, locOrigCrit); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyCritStat failed."); } } private static void ModifyBleedStat(ILCursor c) { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; int num = default(int); if (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[6] { (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0), (Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, 10f), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref num), (Instruction x) => ILPatternMatchingExt.MatchConvR4(x), (Instruction x) => ILPatternMatchingExt.MatchMul(x), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "bleedChance")) })) { int index = c.Index; c.Index = index - 1; c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.bleedChanceAdd)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.bleedChanceMult)); c.Emit(OpCodes.Mul); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyBleedStat failed."); } } private static void ModifyDamageStat(ILCursor c, Action emitLevelMultiplier) { //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; int locBaseDamageIndex = -1; int locDamageMultIndex = -1; if (c.TryGotoNext(new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseDamage"), (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0), (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "levelDamage") }) && c.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref locBaseDamageIndex) }) && c.TryGotoNext(new Func<Instruction, bool>[4] { (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, locBaseDamageIndex), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locDamageMultIndex), (Instruction x) => ILPatternMatchingExt.MatchMul(x), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locBaseDamageIndex) })) { c.GotoPrev(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseDamage") }); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locBaseDamageIndex) }); emitLevelMultiplier(); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float levelMultiplier) => StatMods.baseDamageAdd + StatMods.levelDamageAdd * levelMultiplier)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.damageTotalMult)); c.Emit(OpCodes.Mul); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locDamageMultIndex) }); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float origDamageMult) => origDamageMult + StatMods.damageMultAdd)); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyDamageStat failed."); } } private static void ModifyJumpPowerStat(ILCursor c, Action emitLevelMultiplier) { c.Index = 0; int num = default(int); if (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[6] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseJumpPower"), (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0), (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "levelJumpPower"), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref num), (Instruction x) => ILPatternMatchingExt.MatchMul(x), (Instruction x) => ILPatternMatchingExt.MatchAdd(x) })) { emitLevelMultiplier(); c.EmitDelegate<Func<float, float, float>>((Func<float, float, float>)((float origJumpPower, float levelMultiplier) => (origJumpPower + StatMods.baseJumpPowerAdd + StatMods.levelJumpPowerAdd * levelMultiplier) * (1f + StatMods.jumpPowerMultAdd) * StatMods.jumpPowerTotalMult)); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyJumpPowerStat failed."); } } private static void ModifyJumpCountStat(ILCursor c) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; if (c.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "maxJumpCount")) })) { c.EmitDelegate<Func<int>>((Func<int>)(() => StatMods.jumpCountAdd)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<int>>((Func<int>)(() => StatMods.jumpCountMult)); c.Emit(OpCodes.Mul); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyJumpCountStat failed."); } } private static void ModifyHealthStat(ILCursor c, Action emitLevelMultiplier) { //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; int locBaseHealthIndex = -1; int locHealthMultIndex = -1; if (c.TryGotoNext(new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseMaxHealth"), (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0), (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "levelMaxHealth") }) && c.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref locBaseHealthIndex) }) && c.TryGotoNext(new Func<Instruction, bool>[4] { (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, locBaseHealthIndex), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locHealthMultIndex), (Instruction x) => ILPatternMatchingExt.MatchMul(x), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locBaseHealthIndex) })) { c.GotoPrev(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseMaxHealth") }); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locBaseHealthIndex) }); emitLevelMultiplier(); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float levelMultiplier) => StatMods.baseHealthAdd + StatMods.levelHealthAdd * levelMultiplier)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.healthTotalMult)); c.Emit(OpCodes.Mul); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locHealthMultIndex) }); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.healthMultAdd)); c.Emit(OpCodes.Add); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyHealthStat failed."); } } private static void ModifyShieldStat(ILCursor c, Action emitLevelMultiplier) { //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; int locBaseShieldIndex = -1; if (c.TryGotoNext(new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseMaxShield"), (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0), (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "levelMaxShield") }) && c.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref locBaseShieldIndex) }) && c.TryGotoNext(new Func<Instruction, bool>[2] { (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, locBaseShieldIndex), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "maxShield")) })) { int index = c.Index; c.Index = index + 1; c.EmitDelegate<Func<float>>((Func<float>)(() => 1f + StatMods.shieldMultAdd)); c.Emit(OpCodes.Mul); c.GotoPrev(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "levelMaxShield") }); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref locBaseShieldIndex) }); emitLevelMultiplier(); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float levelMultiplier) => StatMods.baseShieldAdd + StatMods.levelShieldAdd * levelMultiplier)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.shieldTotalMult)); c.Emit(OpCodes.Mul); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyShieldStat failed."); } } private static void ModifyHealthRegenStat(ILCursor c, Action emitLevelMultiplier) { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; int locRegenMultIndex = -1; int locFinalRegenIndex = -1; if (c.TryGotoNext(new Func<Instruction, bool>[2] { (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locFinalRegenIndex), (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertySetter(typeof(CharacterBody), "regen")) }) && c.TryGotoPrev(new Func<Instruction, bool>[4] { (Instruction x) => ILPatternMatchingExt.MatchAdd(x), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locRegenMultIndex), (Instruction x) => ILPatternMatchingExt.MatchMul(x), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref locFinalRegenIndex) })) { c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locRegenMultIndex) }); emitLevelMultiplier(); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float levelMultiplier) => StatMods.baseRegenAdd + StatMods.levelRegenAdd * levelMultiplier)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.regenTotalMult)); c.Emit(OpCodes.Mul); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchMul(x) }); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.regenMultAdd)); c.Emit(OpCodes.Add); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyHealthRegenStat failed."); } } private static void ModifyMovementSpeedStat(ILCursor c, Action emitLevelMultiplier) { //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; int locBaseSpeedIndex = -1; int locSpeedMultIndex = -1; int locSpeedDivIndex = -1; int num2 = default(int); int num = default(int); if (c.TryGotoNext(new Func<Instruction, bool>[3] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "baseMoveSpeed"), (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0), (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "levelMoveSpeed") }) && c.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref locBaseSpeedIndex) }) && c.TryGotoNext(new Func<Instruction, bool>[6] { (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, locBaseSpeedIndex), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locSpeedMultIndex), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref locSpeedDivIndex), (Instruction x) => ILPatternMatchingExt.MatchDiv(x), (Instruction x) => ILPatternMatchingExt.MatchMul(x), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locBaseSpeedIndex) }) && c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[4] { (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref num2), (Instruction x) => ILPatternMatchingExt.MatchOr(x), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref num), (Instruction x) => ILPatternMatchingExt.MatchOr(x) })) { c.EmitDelegate<Func<bool>>((Func<bool>)(() => StatMods.moveSpeedRootCount > 0)); c.Emit(OpCodes.Or); c.GotoPrev(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "levelMoveSpeed") }); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locBaseSpeedIndex) }); emitLevelMultiplier(); c.EmitDelegate<Func<float, float>>((Func<float, float>)((float levelMultiplier) => StatMods.baseMoveSpeedAdd + StatMods.levelMoveSpeedAdd * levelMultiplier)); c.Emit(OpCodes.Add); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.moveSpeedTotalMult)); c.Emit(OpCodes.Mul); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locSpeedMultIndex) }); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.moveSpeedMultAdd)); c.Emit(OpCodes.Add); while (c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "sprintingSpeedMultiplier") })) { c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.sprintSpeedAdd)); c.Emit(OpCodes.Add); } c.GotoPrev((MoveType)2, new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)Reflection.GetPropertyGetter(typeof(CharacterBody), "isSprinting")) }); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate<Func<bool, CharacterBody, bool>>((Func<bool, CharacterBody, bool>)((bool isSprinting, CharacterBody sender) => isSprinting && sender.sprintingSpeedMultiplier + StatMods.sprintSpeedAdd != 0f)); c.GotoNext(new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchStloc(x, locSpeedDivIndex) }); c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.moveSpeedReductionMultAdd)); c.Emit(OpCodes.Add); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyMovementSpeedStat failed."); } } private static void ModifyBarrierDecayRate(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<HealthComponent>(x, "GetBarrierDecayRate") })) { val.Emit(OpCodes.Ldarg_0); val.EmitDelegate<Func<float, HealthComponent, float>>((Func<float, HealthComponent, float>)delegate(float barrierDecayRatePerSecond, HealthComponent healthComponent) { CustomStats customStatsFromBody = GetCustomStatsFromBody(healthComponent.body); if (customStatsFromBody == null) { return barrierDecayRatePerSecond; } if (!customStatsFromBody.barrierDecayFrozen) { barrierDecayRatePerSecond += customStatsFromBody.barrierDecayRateAdd; barrierDecayRatePerSecond *= customStatsFromBody.barrierDecayRateMult; } return barrierDecayRatePerSecond; }); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyBarrierDecayRate failed."); } } private static void ModifyLuckStat(ILCursor c) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) c.Index = 0; if (c.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<CharacterMaster>(x, "set_luck") })) { c.EmitDelegate<Func<float>>((Func<float>)(() => StatMods.luckAdd)); c.Emit(OpCodes.Add); } else { RecalculateStatsPlugin.Logger.LogError((object)"ModifyLuckStat failed."); } } private static bool RoundLuckInCheckRoll(orig_CheckRoll_float_float_CharacterMaster orig, float percentChance, float luck, CharacterMaster effectOriginMaster) { float num = luck % 1f; if (num < 0f) { num += 1f; } luck = ((!(num > float.Epsilon) || !Util.CheckRoll(num * 100f, 0f, (CharacterMaster)null)) ? ((float)Math.Floor(luck)) : ((float)Math.Ceiling(luck))); return orig.Invoke(percentChance, luck, effectOriginMaster); } internal static CustomStats GetCustomStatsFromBody(CharacterBody body) { if ((Object)(object)body == (Object)null) { return null; } return characterCustomStats.GetOrCreateValue(body); } } [BepInPlugin("com.bepis.r2api.recalculatestats", "R2API.RecalculateStats", "1.6.5")] public sealed class RecalculateStatsPlugin : BaseUnityPlugin { internal static ManualLogSource Logger { get; set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; } private void OnDestroy() { RecalculateStatsAPI.UnsetHooks(); } } public static class StandardLevelScaling { public const float Health = 0.3f; public const float Shield = 0.3f; public const float Regen = 0.2f; public const float Damage = 0.2f; } } namespace R2API.AutoVersionGen { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] internal class AutoVersionAttribute : Attribute { } }