Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of R2API RecalculateStats v1.6.6
plugins/R2API.RecalculateStats/R2API.RecalculateStats.dll
Decompiled 3 months 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.6.0")] [assembly: AssemblyInformationalVersion("1.6.6+b1c438ff61e6757167e680b5429318d2c7601ef2")] [assembly: AssemblyProduct("R2API.RecalculateStats")] [assembly: AssemblyTitle("R2API.RecalculateStats")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.6.6.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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected I4, but got Unknown float flatReduction = 0f; flatReduction += 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 += 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.6"; [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; } else if (barrierDecayRatePerSecond > 0f) { barrierDecayRatePerSecond = 0f; } 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.6")] 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 { } }