using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LootClicker;
using LootClicker.Entities;
using LootClicker.Entities.Characters;
using LootClicker.Entities.Monsters;
using LootClicker.Entities.Skills;
using LootClicker.Services;
using Microsoft.CodeAnalysis;
[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("Beyond150")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+185abbc525a82435d08112cf46e76b55a4bf3589")]
[assembly: AssemblyProduct("Beyond 150")]
[assembly: AssemblyTitle("Beyond150")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace LootunMyMod
{
[BepInPlugin("nemonline.lootun.beyond150", "Beyond 150", "1.0.2")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger;
internal static Harmony Harmony;
internal static ConfigEntry<int> MaxAscendancyLevel;
internal static ConfigEntry<float> XpGrowthPerLevel;
internal static ConfigEntry<float> KillXpMultiplier;
internal static ConfigEntry<int> MaxMasteryLevel;
internal static ConfigEntry<float> MasteryXpGrowthPerLevel;
internal static ConfigEntry<int> PassiveMaxRank;
internal static ConfigEntry<int> ClassPassiveMaxRank;
internal static ConfigEntry<int> AscLevelsPerClassPoint;
internal static ConfigEntry<float> ClassRankStep;
internal static void ApplyPatches()
{
int num = 0;
int num2 = 0;
foreach (Type item in from t in AccessTools.GetTypesFromAssembly(typeof(Plugin).Assembly)
orderby (!t.Name.StartsWith("Tasks_") && !t.Name.StartsWith("Points_")) ? 1 : 0
select t)
{
if (!(item == typeof(Locale_SetupLocale_Hook)) && item.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Any())
{
try
{
Harmony.CreateClassProcessor(item).Patch();
num++;
}
catch (Exception arg)
{
num2++;
Logger.LogError((object)$"Patch {item.Name} failed: {arg}");
}
}
}
Class_OnOff_Scaling.LogSummary();
Logger.LogInfo((object)$"Patching done: {num} patch classes applied, {num2} failed");
}
private void Awake()
{
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
MaxAscendancyLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Levels", "MaxAscendancyLevel", 200, "Vanilla 50. Total character level = 100 + this (200 => level 300).");
XpGrowthPerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Levels", "XpGrowthPerLevel", 0.0176f, "XP needed per level above 150 = 38M * (1 + this * (level - 150)). 0.0176 matches monster XP growth (same kills per level as at 150 when fighting your level), 0 = flat 38M per level. The vanilla-formula continuation would be ~0.0316.");
KillXpMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Levels", "KillXpMultiplierAbove150", 1f, "Multiplies XP from kills (character and skill mastery) while a character is above level 150. 2 = twice as fast, 0.5 = longer grind. Levels 1-150 and mission completion rewards are unaffected.");
MaxMasteryLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Mastery", "MaxMasteryLevel", 40, "Vanilla 30. Max base mastery level for skills (gems/enchants still add on top).");
MasteryXpGrowthPerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Mastery", "MasteryXpGrowthPerLevel", 0.063f, "Mastery XP needed above level 30 = XP(29) * (1 + this * (level - 29)), XP(29) ~ 949M. 0.063 ~ continues the vanilla curve, 0 = flat ~949M per level.");
PassiveMaxRank = ((BaseUnityPlugin)this).Config.Bind<int>("Passives", "PassiveMaxRank", 10, "New max rank for class passives (Warrior/Ranger/Mage/Paladin), generic Ascendancy passives and skill mastery passives. Only passives that are above rank 1 in vanilla are changed; rank-1 modifier passives (e.g. Shared Protection) always stay at 1.");
ClassPassiveMaxRank = ((BaseUnityPlugin)this).Config.Bind<int>("Passives", "ClassPassiveMaxRank", 5, "New max rank for Ascendancy class passives (Barbarian Passives etc.) whose effect actually scales with rank. On/off passives stay at 1.");
AscLevelsPerClassPoint = ((BaseUnityPlugin)this).Config.Bind<int>("Passives", "AscendancyLevelsPerClassPoint", 10, "One extra Ascendancy class passive point every N Ascendancy levels above 50.");
ClassRankStep = ((BaseUnityPlugin)this).Config.Bind<float>("Passives", "ClassPassiveRankStep", 0.5f, "Ascendancy class passives: each rank above 1 adds this fraction of the base value (0.5 => rank 5 = 3x base). Applies to all classes' rank-scaling passives.");
Harmony = new Harmony("nemonline.lootun.beyond150");
Harmony.CreateClassProcessor(typeof(Locale_SetupLocale_Hook)).Patch();
Logger.LogInfo((object)(string.Format("{0} loaded: max level {1}, ", "Beyond 150", 100 + MaxAscendancyLevel.Value) + $"passive rank {PassiveMaxRank.Value}, class passive rank {ClassPassiveMaxRank.Value}"));
}
}
[HarmonyPatch(typeof(Locale), "SetupLocale")]
internal static class Locale_SetupLocale_Hook
{
private static bool done;
private static void Postfix()
{
if (!done)
{
done = true;
Plugin.ApplyPatches();
}
}
}
internal static class Util
{
public const int VanillaAscCap = 50;
public const int VanillaMasteryCap = 30;
public const int VanillaLevelCap = 150;
public static int XpPenaltyLevel(Character c)
{
return Math.Min(((Entity)c).Level, 150);
}
private static long ScaleKillXp(Character c, long exp)
{
if (c == null || ((Entity)c).Level <= 150)
{
return exp;
}
float num = Math.Max(0f, Plugin.KillXpMultiplier.Value);
return Math.Max(1L, (long)Math.Round((double)exp * (double)num));
}
public static void AddKillExperience(Character c, long exp, bool fromSave)
{
c.AddExperience(ScaleKillXp(c, exp), fromSave);
}
public static void AddKillSkillExperience(Character c, long exp)
{
c.AddSkillExperience(ScaleKillXp(c, exp));
}
public static int AscendancyLevelCap()
{
if (Tasks.AscendancyLevelCap < 50)
{
return Math.Min(Tasks.AscendancyLevelCap, 50);
}
return Plugin.MaxAscendancyLevel.Value;
}
public static IEnumerable<CodeInstruction> SwapConst(IEnumerable<CodeInstruction> instructions, string where, int from, int to, int expectedHits)
{
int hits = 0;
foreach (CodeInstruction instruction in instructions)
{
if (CodeInstructionExtensions.LoadsConstant(instruction, (long)from))
{
hits++;
yield return new CodeInstruction(OpCodes.Ldc_I4, (object)to)
{
labels = instruction.labels,
blocks = instruction.blocks
};
}
else
{
yield return instruction;
}
}
if (hits == expectedHits)
{
Plugin.Logger.LogInfo((object)$"{where}: replaced {hits}x {from} -> {to}");
}
else
{
Plugin.Logger.LogWarning((object)$"{where}: expected {expectedHits}x {from}, found {hits} (game update?)");
}
}
public static int ExtraLevels(Character c)
{
if (c == null)
{
return 0;
}
Ascendancy ascendancy = c.Ascendancy;
int num = ((ascendancy != null) ? ascendancy.Level : 0);
if (c.Ascendancies != null)
{
foreach (Ascendancy value in c.Ascendancies.Values)
{
if (value != null && value.Level > num)
{
num = value.Level;
}
}
}
return Math.Max(0, num - 50);
}
}
internal static class Ranks
{
private static readonly HashSet<Passive> Done = new HashSet<Passive>();
private static readonly Dictionary<AscendancyClass, HashSet<int>> ScalingClassPassives = new Dictionary<AscendancyClass, HashSet<int>>
{
{
(AscendancyClass)1,
new HashSet<int>
{
1, 2, 3, 4, 5, 6, 7, 9, 10, 11,
13, 14, 15, 16, 17, 18, 19
}
},
{
(AscendancyClass)12,
new HashSet<int>
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 14, 16, 18, 19
}
},
{
(AscendancyClass)2,
new HashSet<int>
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18
}
},
{
(AscendancyClass)3,
new HashSet<int>
{
1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 15, 16, 18, 20
}
},
{
(AscendancyClass)4,
new HashSet<int>
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 11,
12, 13, 14, 15, 16, 17, 18, 19
}
},
{
(AscendancyClass)5,
new HashSet<int>
{
1, 2, 3, 4, 5, 6, 8, 10, 12, 14,
16, 17, 20
}
},
{
(AscendancyClass)6,
new HashSet<int>
{
1, 2, 4, 5, 6, 8, 9, 10, 11, 12,
13, 14, 15, 17, 19
}
},
{
(AscendancyClass)7,
new HashSet<int>
{
1, 3, 5, 7, 8, 9, 11, 12, 13, 14,
15, 16, 20
}
},
{
(AscendancyClass)8,
new HashSet<int>
{
3, 5, 6, 7, 9, 10, 12, 13, 14, 15,
16, 17, 18, 20
}
},
{
(AscendancyClass)9,
new HashSet<int>
{
1, 2, 4, 5, 7, 9, 10, 12, 13, 14,
16, 17, 18, 19
}
},
{
(AscendancyClass)10,
new HashSet<int>
{
1, 3, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 19, 20
}
},
{
(AscendancyClass)11,
new HashSet<int>
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 18, 19
}
}
};
public static void Boost(IEnumerable<Passive> passives)
{
if (passives == null)
{
return;
}
int value = Plugin.PassiveMaxRank.Value;
foreach (Passive passife in passives)
{
if (passife != null && Done.Add(passife) && passife.MaxRank > 1 && passife.MaxRank < value)
{
passife.MaxRank = value;
}
}
}
public static bool IsScalingClassPassive(AscendancyClass cls, int id)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
if (ScalingClassPassives.TryGetValue(cls, out var value))
{
return value.Contains(id);
}
return false;
}
public static void BoostClassPassives(Ascendancy asc)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
if (((asc != null) ? asc.AscendancyPassives : null) == null || !ScalingClassPassives.TryGetValue(asc.Class, out var value))
{
return;
}
int value2 = Plugin.ClassPassiveMaxRank.Value;
for (int i = 0; i < asc.AscendancyPassives.Length; i++)
{
Passive val = asc.AscendancyPassives[i];
if (val != null && value.Contains(i + 1) && Done.Add(val) && val.MaxRank < value2)
{
val.MaxRank = value2;
}
}
}
}
[HarmonyPatch(typeof(Character), "AddExperience")]
internal static class Character_AddExperience_Cap
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
{
return Util.SwapConst(ins, "Character.AddExperience", 50, Plugin.MaxAscendancyLevel.Value, 1);
}
}
[HarmonyPatch(typeof(Character), "SetupExperience")]
internal static class Character_SetupExperience_Cap
{
private const double XpAt150 = 38000000.0;
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
{
MethodInfo vanillaCap = AccessTools.Method(typeof(Tasks), "GetAscendancyLevelCap", (Type[])null, (Type[])null);
MethodInfo ourCap = AccessTools.Method(typeof(Util), "AscendancyLevelCap", (Type[])null, (Type[])null);
int redirected = 0;
foreach (CodeInstruction item in Util.SwapConst(ins, "Character.SetupExperience", 50, Plugin.MaxAscendancyLevel.Value, 1))
{
if (CodeInstructionExtensions.Calls(item, vanillaCap))
{
item.operand = ourCap;
redirected++;
}
yield return item;
}
Plugin.Logger.LogInfo((object)$"Character.SetupExperience: redirected {redirected}x GetAscendancyLevelCap");
}
private static void Postfix(Character __instance)
{
if (__instance.CharacterLevel >= 100 && __instance.MaxExperience != int.MaxValue)
{
int level = ((Entity)__instance).Level;
if (level > 150)
{
double num = 38000000.0 * (1.0 + (double)(Math.Max(0f, Plugin.XpGrowthPerLevel.Value) * (float)(level - 150)));
__instance.MaxExperience = ((num >= 2147483646.0) ? 2147483646 : Math.Max(1, (int)num));
}
}
}
}
[HarmonyPatch(typeof(Monster), "GrantExperience")]
internal static class Monster_GrantExperience_Penalty
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
MethodInfo penaltyLevel = AccessTools.Method(typeof(Util), "XpPenaltyLevel", (Type[])null, (Type[])null);
MethodInfo addXp = AccessTools.Method(typeof(Util), "AddKillExperience", (Type[])null, (Type[])null);
MethodInfo addSkillXp = AccessTools.Method(typeof(Util), "AddKillSkillExperience", (Type[])null, (Type[])null);
int level = 0;
int xp = 0;
int skillXp = 0;
foreach (CodeInstruction instruction in instructions)
{
if ((instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Call) && instruction.operand is MethodInfo methodInfo)
{
MethodInfo methodInfo2 = ((methodInfo.Name == "get_Level") ? penaltyLevel : ((methodInfo.Name == "AddExperience" && methodInfo.DeclaringType == typeof(Character)) ? addXp : ((methodInfo.Name == "AddSkillExperience" && methodInfo.DeclaringType == typeof(Character)) ? addSkillXp : null)));
if (methodInfo2 != null)
{
if (methodInfo2 == penaltyLevel)
{
level++;
}
else if (methodInfo2 == addXp)
{
xp++;
}
else
{
skillXp++;
}
yield return new CodeInstruction(OpCodes.Call, (object)methodInfo2)
{
labels = instruction.labels,
blocks = instruction.blocks
};
continue;
}
}
yield return instruction;
}
if (level == 1 && xp == 1 && skillXp == 1)
{
Plugin.Logger.LogInfo((object)"Monster.GrantExperience: XP level penalty capped at 150, kill XP multiplier hooked");
}
else
{
Plugin.Logger.LogWarning((object)$"Monster.GrantExperience: expected 1/1/1 (get_Level/AddExperience/AddSkillExperience), found {level}/{xp}/{skillXp}");
}
}
}
[HarmonyPatch(typeof(Tasks), "GetAscendancyLevelCap")]
internal static class Tasks_GetAscendancyLevelCap
{
private static void Postfix(ref int __result)
{
__result = Util.AscendancyLevelCap();
}
}
[HarmonyPatch(typeof(Character), "SetupPassives")]
internal static class Character_SetupPassives_Ranks
{
private static void Postfix(Character __instance)
{
Ranks.Boost((IEnumerable<Passive>)__instance.Passives);
}
}
[HarmonyPatch]
internal static class Ascendancy_Ctor_Ranks
{
private static IEnumerable<MethodBase> TargetMethods()
{
return AccessTools.GetDeclaredConstructors(typeof(Ascendancy), (bool?)null);
}
private static void Postfix(Ascendancy __instance)
{
Ranks.Boost(__instance.GenericPassives);
Ranks.BoostClassPassives(__instance);
}
}
[HarmonyPatch]
internal static class Skill_GeneratePassives_Ranks
{
private static IEnumerable<MethodBase> TargetMethods()
{
return from t in typeof(Skill).Assembly.GetTypes()
where !t.IsAbstract && typeof(Skill).IsAssignableFrom(t)
select AccessTools.DeclaredMethod(t, "GeneratePassives", (Type[])null, (Type[])null) into m
where m != null
select m;
}
private static void Postfix(Skill __instance)
{
if (!(__instance is FactionCooldown))
{
Ranks.Boost(__instance.Passives);
}
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class Points_Class
{
private static void Postfix(Character __instance, ref int __result)
{
int num = Util.ExtraLevels(__instance);
int num2 = num / 5;
int num3 = num % 5;
__result += 2 * num2 + ((num3 >= 2) ? 2 : ((num3 >= 1) ? 1 : 0));
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class Points_DefaultAttack
{
private static void Postfix(Character __instance, ref int __result)
{
int num = Util.ExtraLevels(__instance);
__result += num / 5 + ((num % 5 >= 3) ? 1 : 0);
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class Points_Offensive
{
private static void Postfix(Character __instance, ref int __result)
{
int num = Util.ExtraLevels(__instance);
__result += num / 5 + ((num % 5 >= 4) ? 1 : 0);
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class Points_Defensive
{
private static void Postfix(Character __instance, ref int __result)
{
__result += Util.ExtraLevels(__instance) / 5;
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class Points_AscendancyClass
{
private static void Postfix(Ascendancy __instance, ref int __result)
{
int num = __instance.Level - 50;
if (num > 0)
{
__result += num / Math.Max(1, Plugin.AscLevelsPerClassPoint.Value);
}
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class Points_AscendancyGeneric
{
private static void Postfix(Ascendancy __instance, ref int __result)
{
int level = __instance.Level;
__result = ((level > 0) ? (level - Math.Min(level / 5 + 1, 10)) : 0);
}
}
internal static class ClassScaling
{
public static double Mult(int rank)
{
if (rank > 0)
{
return 1.0 + (double)(Plugin.ClassRankStep.Value * (float)(rank - 1));
}
return 0.0;
}
public static int Rank(Ascendancy asc, int id)
{
Passive[] array = ((asc != null) ? asc.AscendancyPassives : null);
if (array == null || id < 1 || id > array.Length)
{
return 0;
}
Passive obj = array[id - 1];
if (obj == null)
{
return 0;
}
return obj.CurrentRank;
}
public static int ScaleByRank(int baseValue, int rank)
{
return (int)Math.Round((double)baseValue * Mult(rank));
}
public static int ScaleInt(int value, Ascendancy asc, int id)
{
return (int)Math.Round((double)value * Mult(Math.Max(1, Rank(asc, id))));
}
public static double ScaleDouble(double value, Ascendancy asc, int id)
{
return value * Mult(Math.Max(1, Rank(asc, id)));
}
}
[HarmonyPatch]
internal static class Ascendancy_UpdatePassive_Scaling
{
private static IEnumerable<MethodBase> TargetMethods()
{
return from t in typeof(Ascendancy).Assembly.GetTypes()
where !t.IsAbstract && t.IsSubclassOf(typeof(Ascendancy))
select AccessTools.DeclaredMethod(t, "UpdateAscendancyPassive", (Type[])null, (Type[])null) into m
where m != null
select m;
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Expected O, but got Unknown
List<CodeInstruction> list = instructions.ToList();
MethodInfo methodInfo = AccessTools.Method(typeof(ClassScaling), "ScaleByRank", (Type[])null, (Type[])null);
int num = 0;
for (int i = 1; i < list.Count - 1; i++)
{
if (CodeInstructionExtensions.LoadsConstant(list[i - 1]) && CodeInstructionExtensions.IsLdarg(list[i], (int?)2) && list[i + 1].opcode == OpCodes.Mul)
{
list[i + 1] = new CodeInstruction(OpCodes.Call, (object)methodInfo)
{
labels = list[i + 1].labels,
blocks = list[i + 1].blocks
};
num++;
}
}
Plugin.Logger.LogInfo((object)$"{original.DeclaringType?.Name}.UpdateAscendancyPassive: {num} rank-scaled value(s)");
return list;
}
}
internal class ConstSpec
{
public Type Class;
public string Method;
public int PassiveId;
public long IntValue;
public double? DoubleValue;
public string NextCall;
public long? NextConst;
public OpCode? NextOp;
public bool VarMul;
public int Occurrence = -1;
public int Expected = 1;
public string Label => $"{Class.Name}.{Method}: passive {PassiveId}";
public bool Matches(List<CodeInstruction> l, int i)
{
if (!(DoubleValue.HasValue ? CodeInstructionExtensions.LoadsConstant(l[i], DoubleValue.Value) : CodeInstructionExtensions.LoadsConstant(l[i], IntValue)))
{
return false;
}
if (NextCall != null)
{
if (l[i + 1].operand is MethodInfo methodInfo)
{
return methodInfo.Name == NextCall;
}
return false;
}
if (NextConst.HasValue)
{
return CodeInstructionExtensions.LoadsConstant(l[i + 1], NextConst.Value);
}
if (NextOp.HasValue)
{
return l[i + 1].opcode == NextOp.Value;
}
if (VarMul)
{
if (i + 2 < l.Count && (CodeInstructionExtensions.IsLdloc(l[i + 1], (LocalBuilder)null) || CodeInstructionExtensions.IsLdarg(l[i + 1], (int?)null)))
{
return l[i + 2].opcode == OpCodes.Mul;
}
return false;
}
return true;
}
}
[HarmonyPatch]
internal static class Class_OnOff_Scaling
{
private static readonly OpCode Add = OpCodes.Add;
private static readonly OpCode Mul = OpCodes.Mul;
private const string MoreDmg = "AddMoreDamageOverride";
private const string SetValue = "set_Value";
private const string Proc = "CheckProc";
private const string ReduceCd = "ReduceCooldown";
private const string Stacks = "AddStackValue";
private static readonly Type Barb = typeof(Barbarian);
private static readonly Type Temp = typeof(Templar);
private static readonly Type Jugg = typeof(Juggernaut);
private static readonly Type Ward = typeof(Warden);
private static readonly Type Assa = typeof(Assassin);
private static readonly Type Mark = typeof(Marksman);
private static readonly Type Rene = typeof(Renegade);
private static readonly Type Arch = typeof(Archmage);
private static readonly Type Vizi = typeof(Vizier);
private static readonly Type Batt = typeof(Battlemage);
private static readonly Type Crus = typeof(Crusader);
private static readonly Type Inqu = typeof(Inquisitor);
private static readonly ConstSpec[] Specs;
internal static int Mismatches;
private static readonly Dictionary<(Type, int), string> Notes;
private static ConstSpec I(Type t, string m, int id, long v, string call = null, long? next = null, OpCode? op = null, bool varMul = false, int occ = -1, int exp = 1)
{
return new ConstSpec
{
Class = t,
Method = m,
PassiveId = id,
IntValue = v,
NextCall = call,
NextConst = next,
NextOp = op,
VarMul = varMul,
Occurrence = occ,
Expected = exp
};
}
private static ConstSpec D(Type t, string m, int id, double v, int occ = -1, int exp = 1)
{
return new ConstSpec
{
Class = t,
Method = m,
PassiveId = id,
DoubleValue = v,
Occurrence = occ,
Expected = exp
};
}
private static IEnumerable<MethodBase> TargetMethods()
{
return from m in Specs.Select((ConstSpec s) => (Class: s.Class, Method: s.Method)).Distinct().Select<(Type, string), MethodBase>((Func<(Type, string), MethodBase>)(((Type Class, string Method) x) => AccessTools.Method(x.Class, x.Method, (Type[])null, (Type[])null)))
where m != null
select m;
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
{
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Expected O, but got Unknown
//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
//IL_01d5: Expected O, but got Unknown
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f4: Expected O, but got Unknown
List<CodeInstruction> list = instructions.ToList();
MethodInfo methodInfo = AccessTools.Method(typeof(ClassScaling), "ScaleInt", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(ClassScaling), "ScaleDouble", (Type[])null, (Type[])null);
List<(int, ConstSpec)> list2 = new List<(int, ConstSpec)>();
foreach (ConstSpec item in Specs.Where((ConstSpec s) => s.Class == original.DeclaringType && s.Method == original.Name))
{
int num = 0;
int num2 = 0;
for (int num3 = 0; num3 < list.Count - 1; num3++)
{
if (item.Matches(list, num3) && (item.Occurrence < 0 || num++ == item.Occurrence))
{
list2.Add((num3, item));
num2++;
}
}
if (num2 == item.Expected)
{
Plugin.Logger.LogDebug((object)(item.Label + " now rank-scaling"));
continue;
}
Mismatches++;
Plugin.Logger.LogWarning((object)$"{item.Label} expected {item.Expected} match(es), found {num2}");
}
foreach (var (num4, constSpec) in list2.OrderByDescending<(int, ConstSpec), int>(((int index, ConstSpec spec) x) => x.index))
{
list.InsertRange(num4 + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[3]
{
new CodeInstruction(OpCodes.Ldarg_0, (object)null),
new CodeInstruction(OpCodes.Ldc_I4, (object)constSpec.PassiveId),
new CodeInstruction(OpCodes.Call, (object)(constSpec.DoubleValue.HasValue ? methodInfo2 : methodInfo))
});
}
return list;
}
internal static string ScaledWhat(Ascendancy asc, int id)
{
if (asc == null || !Notes.TryGetValue((((object)asc).GetType(), id), out var value))
{
return "values";
}
return value;
}
internal static void LogSummary()
{
Plugin.Logger.LogInfo((object)($"Class passive scaling: {Specs.Length - Mismatches}/{Specs.Length} value specs matched" + ((Mismatches > 0) ? " (see warnings above)" : "")));
}
static Class_OnOff_Scaling()
{
ConstSpec[] obj = new ConstSpec[183]
{
I(Barb, "OnTargetAttacked", 1, 100L, "AddMoreDamageOverride"),
I(Barb, "OnTargetAttacked", 2, 100L, "set_Value"),
I(Barb, "OnTargetAttacked", 6, 200L, "CheckProc"),
I(Barb, "OnTargetAttacked", 7, 3L, null, 5L),
I(Barb, "OnTargetAttacked", 9, 120L, "AddMoreDamageOverride"),
I(Barb, "OnTargetHit", 3, 30L, "AddStackValue"),
I(Barb, "OnTargetHit", 18, 50L, "ReduceCooldown", null, null, varMul: false, 0),
I(Barb, "OnTargetHit", 19, 50L, "ReduceCooldown", null, null, varMul: false, 1),
I(Barb, "OnSkillCompleted", 10, 1000L),
D(Barb, "OnSkillCast", 14, 0.2),
D(Barb, "OnMonsterSlain", 4, 0.1),
I(Barb, "OnHealthChanged", 11, 1000L, "set_Value"),
I(Barb, "OnHealthChanged", 17, 200L, "set_Value"),
I(Temp, "OnEquip", 1, 100L),
D(Temp, "OnBlock", 4, 0.02, 0),
D(Temp, "OnBlock", 8, 0.02, 1),
I(Temp, "OnBlock", 7, 250L, "set_Value"),
I(Temp, "OnBlock", 7, 100L, "set_Value"),
I(Temp, "OnBlock", 9, 500L, "ReduceCooldown", null, null, varMul: false, 0),
I(Temp, "OnBlock", 10, 500L, "ReduceCooldown", null, null, varMul: false, 1),
I(Temp, "OnBlock", 11, 80L, null, 10000L),
I(Temp, "OnBlock", 16, 4L, null, 10000L),
I(Temp, "OnTargetAttacked", 5, 100L, "AddMoreDamageOverride", null, null, varMul: false, 0),
I(Temp, "OnTargetAttacked", 6, 100L, "AddMoreDamageOverride", null, null, varMul: false, 1),
D(Temp, "OnTargetAttacked", 14, 0.03),
D(Temp, "OnTargetAttacked", 18, 0.25),
D(Temp, "OnThornsAttack", 18, 0.25),
D(Temp, "OnMaxHealthChanged", 19, 0.02),
I(Jugg, "OnTickUpdate", 1, 500L, "set_Value"),
I(Jugg, "OnTickUpdate", 5, 250L, "set_Value"),
I(Jugg, "OnTickUpdate", 5, 1250L, "set_Value"),
I(Jugg, "OnTargetAttacked", 2, 100L, "AddMoreDamageOverride"),
I(Jugg, "OnTargetAttacked", 6, 500L, "AddMoreDamageOverride"),
I(Jugg, "OnTargetAttacked", 13, 250L, "AddMoreDamageOverride"),
I(Jugg, "OnTargetAttacked", 18, 150L, "AddMoreDamageOverride"),
D(Jugg, "OnTargetAttacked", 17, 0.03),
I(Jugg, "OnDamageTaken", 3, 10L, "set_Value"),
I(Jugg, "OnDamageTaken", 7, 10L, "AddStackValue"),
I(Jugg, "OnDamageTaken", 11, 150L, "set_Value"),
I(Jugg, "OnHealthChanged", 8, -100L, "set_Value"),
I(Jugg, "OnHealthChanged", 16, 500L, "set_Value"),
D(Jugg, "OnMaxHealthChanged", 12, 0.01),
D(Jugg, "OnMaxHealthChanged", 15, 0.03),
I(Jugg, "OnSkillCompleted", 10, 20L, "CheckProc"),
I(Jugg, "OnSkillCastFinal", 14, 30L, "CheckProc"),
I(Ward, "OnBlock", 1, 300L, "set_Value"),
I(Ward, "OnBlock", 5, 250L, "set_Value", null, null, varMul: false, 0),
I(Ward, "OnBlock", 5, 1250L, "set_Value"),
D(Ward, "OnBlock", 3, 0.03, 0),
D(Ward, "OnBlock", 7, 0.03, 1),
I(Ward, "OnBlock", 6, 200L),
I(Ward, "OnBlock", 9, 10L, "AddStackValue"),
I(Ward, "OnBlock", 11, 100L, "CheckProc", null, null, varMul: false, 0),
I(Ward, "OnBlock", 15, 100L, "CheckProc", null, null, varMul: false, 1),
I(Ward, "OnBlock", 12, 250L, "set_Value", null, null, varMul: false, 1),
I(Ward, "OnBlock", 16, 100L, "set_Value"),
I(Ward, "OnBlock", 18, 1000L, "ReduceCooldown"),
I(Ward, "OnTargetHit", 4, 20L, "Min"),
I(Ward, "OnTargetAttacked", 10, 250L, "AddMoreDamageOverride"),
I(Ward, "OnTargetAttacked", 13, 100L, "AddMoreDamageOverride"),
D(Ward, "OnDamageTaken", 20, 0.1),
I(Assa, "OnTargetAttacked", 1, 100L, "AddMoreDamageOverride"),
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null
};
Type assa = Assa;
long v = 150L;
OpCode? op = Add;
obj[62] = I(assa, "OnTargetAttacked", 2, v, null, null, op);
obj[63] = I(Assa, "OnTargetAttacked", 6, 300L, "AddMoreDamageOverride");
obj[64] = I(Assa, "OnTargetAttacked", 9, 200L, "CheckProc");
Type assa2 = Assa;
long v2 = 100L;
op = Add;
obj[65] = I(assa2, "OnTargetAttacked", 18, v2, null, null, op);
Type assa3 = Assa;
long v3 = 500L;
op = Add;
obj[66] = I(assa3, "OnTargetAttacked", 18, v3, null, null, op);
Type assa4 = Assa;
long v4 = 100L;
op = Add;
obj[67] = I(assa4, "OnThornsAttack", 18, v4, null, null, op);
Type assa5 = Assa;
long v5 = 500L;
op = Add;
obj[68] = I(assa5, "OnThornsAttack", 18, v5, null, null, op);
obj[69] = I(Assa, "OnTargetHit", 3, 30L, "AddStackValue");
obj[70] = I(Assa, "OnTargetHit", 7, 100L, "set_Value");
obj[71] = D(Assa, "OnMonsterSlain", 4, 0.1, 0);
obj[72] = D(Assa, "OnMonsterSlain", 8, 0.1, 1);
obj[73] = I(Assa, "OnMonsterSlain", 12, -150L, "set_Value");
obj[74] = I(Assa, "OnMonsterSlain", 16, 100L, "set_Value");
obj[75] = I(Assa, "OnMonsterSlain", 16, 50L, "set_Value");
obj[76] = I(Assa, "OnMonsterSlain", 14, 2000L, "ReduceCooldown");
obj[77] = D(Assa, "OnDodge", 11, 0.05, -1, 2);
obj[78] = D(Assa, "OnEvade", 11, 0.05, -1, 2);
obj[79] = I(Assa, "OnDodge", 15, 1000L, "ReduceCooldown");
obj[80] = I(Assa, "OnEvade", 15, 1000L, "ReduceCooldown");
obj[81] = I(Assa, "OnSkillCompleted", 19, 500L);
obj[82] = I(Mark, "OnSkillCast", 1, 15L, null, 0L);
obj[83] = I(Mark, "OnTargetFirstHit", 5, 5L, null, 0L);
obj[84] = I(Mark, "OnTargetAttacked", 6, 100L, "AddMoreDamageOverride");
obj[85] = I(Mark, "ApplyFocusStacks", 2, 5L, null, null, null, varMul: true, 0);
obj[86] = I(Mark, "ApplyFocusStacks", 10, 5L, null, null, null, varMul: true, 1);
obj[87] = I(Mark, "ApplyFocusStacks", 12, 15L, null, null, null, varMul: true);
obj[88] = I(Mark, "ApplyFocusStacks", 20, 2L, null, null, null, varMul: true, -1, 2);
obj[89] = I(Mark, "LoseFocusStacks", 3, 120L, "set_Value", null, null, varMul: false, 0);
obj[90] = I(Mark, "LoseFocusStacks", 17, 120L, "set_Value", null, null, varMul: false, 1);
obj[91] = I(Mark, "LoseFocusStacks", 4, 100L, "set_Value");
Type mark = Mark;
long v6 = 50L;
op = Mul;
obj[92] = I(mark, "LoseFocusStacks", 14, v6, null, null, op, varMul: false, 0);
Type mark2 = Mark;
long v7 = 50L;
op = Mul;
obj[93] = I(mark2, "LoseFocusStacks", 16, v7, null, null, op, varMul: false, 1);
obj[94] = I(Mark, "OnDamageTaken", 8, 5L, null, null, null, varMul: true);
obj[95] = I(Rene, "OnStaggerChanged", 1, 120L, "set_Value");
obj[96] = I(Rene, "OnStaggerChanged", 10, 20L, null, null, null, varMul: true, 0);
obj[97] = I(Rene, "OnStaggerChanged", 19, 20L, null, null, null, varMul: true, 1);
obj[98] = I(Rene, "ApplySwiftReflexes", 2, 10L, "AddStackValue");
obj[99] = I(Rene, "ApplySwiftReflexes", 6, 100L, "set_Value");
obj[100] = I(Rene, "OnEncounterLoopStart", 5, 40L, "set_Value", null, null, varMul: false, -1, 2);
obj[101] = I(Rene, "OnEncounterLoopStart", 9, 50L, "set_Value");
obj[102] = I(Rene, "OnDotStacksRemoved", 4, 50L, null, null, null, varMul: true, -1, 2);
obj[103] = I(Rene, "OnDotStacksRemoved", 12, 100L, "set_Value");
obj[104] = I(Rene, "OnDotStacksRemoved", 13, 100L, null, null, null, varMul: true, 0);
obj[105] = I(Rene, "OnDotStacksRemoved", 15, 100L, null, null, null, varMul: true, 1);
Type rene = Rene;
long v8 = 5L;
op = Mul;
obj[106] = I(rene, "OnHealthChanged", 11, v8, null, null, op);
obj[107] = I(Rene, "OnTargetAttacked", 14, 100L, "AddMoreDamageOverride");
obj[108] = I(Rene, "OnTargetAttacked", 17, 200L, "AddMoreDamageOverride");
obj[109] = I(Arch, "ApplyElementalBlastSuccess", 1, 100L, "set_Value", null, null, varMul: false, 0);
obj[110] = I(Arch, "ApplyElementalBlastSuccess", 5, 100L, "set_Value", null, null, varMul: false, 1);
obj[111] = I(Arch, "ApplyElementalBlastSuccess", 20, 100L, "set_Value", null, null, varMul: false, 2);
obj[112] = D(Arch, "ApplyElementalBlastSuccess", 3, 0.025);
obj[113] = D(Arch, "ApplyElementalBlastSuccess", 16, 0.05);
obj[114] = I(Arch, "ApplyElementalBlastSuccess", 14, 150L, "ReduceCooldown", null, null, varMul: false, 0);
obj[115] = I(Arch, "ApplyElementalBlastSuccess", 15, 150L, "ReduceCooldown", null, null, varMul: false, 1);
obj[116] = I(Arch, "ApplyElementalBlastTargetHit", 13, -150L, "set_Value");
obj[117] = I(Arch, "OnTargetAttacked", 7, 100L, "AddMoreDamageOverride");
obj[118] = I(Arch, "OnChilled", 11, 100L, "set_Value");
obj[119] = I(Arch, "OnShocked", 12, 100L, "set_Value");
obj[120] = I(Arch, "OnSkillCompleted", 8, 5L);
obj[121] = D(Vizi, "ApplyVizierTargetHit", 3, 0.01, 0);
obj[122] = D(Vizi, "ApplyVizierTargetHit", 7, 0.01, 1);
obj[123] = I(Vizi, "ApplyVizierTargetHit", 17, 50L, "ReduceCooldown", null, null, varMul: false, 0);
obj[124] = I(Vizi, "ApplyVizierTargetHit", 20, 50L, "ReduceCooldown", null, null, varMul: false, 1);
obj[125] = I(Vizi, "OnTargetAttacked", 5, 250L, "AddMoreDamageOverride", null, null, varMul: false, 0);
obj[126] = I(Vizi, "OnTargetAttacked", 6, 250L, "AddMoreDamageOverride", null, null, varMul: false, 1);
obj[127] = I(Vizi, "OnTargetAttacked", 13, 1500L, "AddMoreDamageOverride");
obj[128] = I(Vizi, "OnTargetAttacked", 15, 100L, "AddMoreDamageOverride");
obj[129] = I(Vizi, "OnTargetAttacked", 18, 120L, "AddMoreDamageOverride");
obj[130] = I(Vizi, "AddPowerCharges", 9, 200L, "set_Value");
obj[131] = I(Vizi, "AddPowerCharges", 14, 120L, "set_Value");
obj[132] = I(Vizi, "AddPowerCharges", 16, 100L, "set_Value");
obj[133] = I(Vizi, "AddMirrorImageStacks", 12, 100L, "set_Heal");
obj[134] = I(Batt, "OnBarrierChanged", 1, 100L, "set_Value", null, null, varMul: false, 0);
obj[135] = I(Batt, "OnBarrierChanged", 9, 100L, "set_Value", null, null, varMul: false, 1);
obj[136] = I(Batt, "OnBarrierChanged", 17, 100L, "set_Value", null, null, varMul: false, 2);
obj[137] = I(Batt, "OnBarrierChanged", 7, 400L, "set_Value");
obj[138] = D(Batt, "OnTargetHit", 4, 0.005, -1, 2);
obj[139] = I(Batt, "OnTargetHit", 14, 50L, "ReduceCooldown");
obj[140] = I(Batt, "OnDamageTaken", 5, 500L, "set_Value");
obj[141] = I(Batt, "OnDamageTaken", 16, 100L, "set_Value");
obj[142] = I(Batt, "OnTargetAttacked", 13, 100L, "AddMoreDamageOverride");
obj[143] = D(Batt, "OnTargetAttacked", 18, 0.01);
obj[144] = D(Batt, "OnMaxBarrierChanged", 19, 0.01, -1, 2);
obj[145] = D(Batt, "OnRegenTick", 10, 0.1);
obj[146] = I(Crus, "OnTargetAttacked", 1, 120L, "AddMoreDamageOverride");
Type crus = Crus;
long v9 = 30L;
op = Mul;
obj[147] = I(crus, "OnTargetAttacked", 7, v9, null, null, op);
Type crus2 = Crus;
long v10 = 150L;
op = Mul;
obj[148] = I(crus2, "OnTargetAttacked", 7, v10, null, null, op);
Type crus3 = Crus;
long v11 = 30L;
op = Mul;
obj[149] = I(crus3, "OnThornsAttack", 7, v11, null, null, op);
Type crus4 = Crus;
long v12 = 150L;
op = Mul;
obj[150] = I(crus4, "OnThornsAttack", 7, v12, null, null, op);
obj[151] = I(Crus, "OnTargetAttacked", 8, 200L, "CheckProc");
Type crus5 = Crus;
long v13 = 150L;
op = Add;
obj[152] = I(crus5, "OnTargetAttacked", 11, v13, null, null, op);
Type crus6 = Crus;
long v14 = 300L;
op = Add;
obj[153] = I(crus6, "UpdateBlessingStrength", 9, v14, null, null, op);
Type crus7 = Crus;
long v15 = 50L;
op = Add;
obj[154] = I(crus7, "UpdateBlessingStrength", 10, v15, null, null, op, varMul: false, 0);
Type crus8 = Crus;
long v16 = 50L;
op = Add;
obj[155] = I(crus8, "UpdateBlessingStrength", 12, v16, null, null, op, varMul: false, 1);
Type crus9 = Crus;
long v17 = 50L;
op = Add;
obj[156] = I(crus9, "UpdateBlessingStrength", 13, v17, null, null, op, varMul: false, 2);
Type crus10 = Crus;
long v18 = 50L;
op = Add;
obj[157] = I(crus10, "UpdateBlessingStrength", 16, v18, null, null, op, varMul: false, 3);
obj[158] = I(Crus, "OnSkillCast", 10, 50L, "CheckProc", null, null, varMul: false, 0);
obj[159] = I(Crus, "OnSkillCast", 12, 50L, "CheckProc", null, null, varMul: false, 1);
obj[160] = I(Crus, "OnSkillCast", 13, 50L, "CheckProc", null, null, varMul: false, 2);
obj[161] = I(Crus, "OnSkillCast", 16, 50L, "CheckProc", null, null, varMul: false, 3);
obj[162] = D(Crus, "OnSkillCast", 3, 0.004, -1, 2);
obj[163] = D(Crus, "OnSkillCast", 20, 0.02, -1, 2);
obj[164] = I(Crus, "OnSkillCast", 14, 250L, "ReduceCooldown", null, null, varMul: false, 0);
obj[165] = I(Crus, "OnSkillCast", 15, 250L, "ReduceCooldown", null, null, varMul: false, 1);
obj[166] = D(Crus, "OnMaxHealthChanged", 19, 0.03);
obj[167] = I(Inqu, "OnTargetAttacked", 1, 100L, "AddMoreDamageOverride", null, null, varMul: false, 0);
obj[168] = I(Inqu, "OnTargetAttacked", 13, 100L, "AddMoreDamageOverride", null, null, varMul: false, 1);
obj[169] = I(Inqu, "OnTargetAttacked", 6, 200L, "CheckProc");
Type inqu = Inqu;
long v19 = 100L;
op = Add;
obj[170] = I(inqu, "OnTargetAttacked", 10, v19, null, null, op);
Type inqu2 = Inqu;
long v20 = 500L;
op = Add;
obj[171] = I(inqu2, "OnTargetAttacked", 10, v20, null, null, op);
Type inqu3 = Inqu;
long v21 = 100L;
op = Add;
obj[172] = I(inqu3, "OnThornsAttack", 10, v21, null, null, op);
Type inqu4 = Inqu;
long v22 = 500L;
op = Add;
obj[173] = I(inqu4, "OnThornsAttack", 10, v22, null, null, op);
obj[174] = I(Inqu, "OnTargetHit", 2, 30L, "AddStackValue");
obj[175] = D(Inqu, "OnTargetHit", 8, 0.005, -1, 2);
obj[176] = I(Inqu, "OnTargetHit", 15, 50L, "ReduceCooldown", null, null, varMul: false, 0);
obj[177] = I(Inqu, "OnTargetHit", 16, 50L, "ReduceCooldown", null, null, varMul: false, 1);
obj[178] = D(Inqu, "OnMonsterSlain", 4, 0.1, -1, 2);
obj[179] = I(Inqu, "OnBarrierChanged", 11, 100L);
obj[180] = I(Inqu, "OnSkillCast", 14, 100L, "CheckProc");
obj[181] = I(Inqu, "OnSkillCast", 14, 80L, null, 5000L);
obj[182] = D(Inqu, "UpdateProtectiveInvocation", 19, 0.005, -1, 2);
Specs = obj;
Notes = new Dictionary<(Type, int), string>
{
{
(typeof(Barbarian), 3),
"max stacks"
},
{
(typeof(Assassin), 3),
"max stacks"
},
{
(typeof(Inquisitor), 2),
"max stacks"
},
{
(typeof(Juggernaut), 7),
"max stacks"
},
{
(typeof(Warden), 4),
"max stacks"
},
{
(typeof(Warden), 9),
"max stacks"
},
{
(typeof(Renegade), 2),
"max stacks"
},
{
(typeof(Archmage), 8),
"number of targets"
},
{
(typeof(Marksman), 1),
"focus stacks gained"
},
{
(typeof(Marksman), 5),
"focus stacks gained"
}
};
}
}
[HarmonyPatch(typeof(MasterySkill), "SetupExperience")]
internal static class Mastery_SetupExperience
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
{
return Util.SwapConst(ins, "MasterySkill.SetupExperience", 30, Plugin.MaxMasteryLevel.Value, 1);
}
private static void Postfix(MasterySkill __instance)
{
int baseMasteryLevel = __instance.BaseMasteryLevel;
if (baseMasteryLevel >= 30)
{
int value = Plugin.MaxMasteryLevel.Value;
int num = Math.Min(baseMasteryLevel, value - 1);
double num2 = (double)__instance.MaxExperience * (1.0 + (double)(Math.Max(0f, Plugin.MasteryXpGrowthPerLevel.Value) * (float)(num - 29)));
__instance.MaxExperience = ((num2 >= 2147483646.0) ? 2147483646 : Math.Max(1, (int)num2));
if (baseMasteryLevel >= value)
{
__instance.CurrentExperience = __instance.MaxExperience;
}
}
}
}
[HarmonyPatch(typeof(MasterySkill), "AddMasteryExperience")]
internal static class Mastery_AddMasteryExperience
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
{
return Util.SwapConst(ins, "MasterySkill.AddMasteryExperience", 30, Plugin.MaxMasteryLevel.Value, 2);
}
}
[HarmonyPatch(typeof(MasteryPassivePanelController), "UpdateSkillInfoPanel")]
internal static class Mastery_InfoPanel
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
{
return Util.SwapConst(ins, "MasteryPassivePanelController.UpdateSkillInfoPanel", 30, Plugin.MaxMasteryLevel.Value, 1);
}
}
[HarmonyPatch(typeof(SaveFile), "LoadMasterySkill")]
internal static class Mastery_LoadMasterySkill
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
{
return Util.SwapConst(ins, "SaveFile.LoadMasterySkill", 30, Plugin.MaxMasteryLevel.Value, 1);
}
}
[HarmonyPatch(typeof(SaveFile), "LoadFactionCooldown")]
internal static class Mastery_LoadFactionCooldown
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
{
return Util.SwapConst(ins, "SaveFile.LoadFactionCooldown", 30, Plugin.MaxMasteryLevel.Value, 1);
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class AscendancyPassive_Tooltip
{
private static string Pct(int rank)
{
return $"{Math.Round(ClassScaling.Mult(rank) * 100.0)}%";
}
private static void Postfix(AscendancyPassive __instance, ref string __result)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
if (!string.IsNullOrEmpty(__result) && ((Passive)__instance).MaxRank > 1)
{
Ascendancy value = Traverse.Create((object)__instance).Property("Ascendancy", (object[])null).GetValue<Ascendancy>();
if (value != null && Ranks.IsScalingClassPassive(value.Class, ((Passive)__instance).ID))
{
int currentRank = ((Passive)__instance).CurrentRank;
int maxRank = ((Passive)__instance).MaxRank;
string text = Class_OnOff_Scaling.ScaledWhat(value, ((Passive)__instance).ID);
string text2 = ((currentRank <= 0) ? $"Scales with rank: up to {Pct(maxRank)} of listed {text} at rank {maxRank}" : ((currentRank < maxRank) ? ("Current effect: " + Pct(currentRank) + " of listed " + text + " (next rank: " + Pct(currentRank + 1) + ")") : ("Current effect: " + Pct(currentRank) + " of listed " + text + " (max rank)")));
string text3 = "\n" + TextHelper.GetHtmlText(text2, "#95FF6D", false, -1);
string htmlText = TextHelper.GetHtmlText(((Passive)__instance).Description, "#518AD6", false, -1);
int num = __result.IndexOf(htmlText, StringComparison.Ordinal);
__result = ((num >= 0) ? __result.Insert(num + htmlText.Length, text3) : (__result + text3));
}
}
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "nemonline.lootun.beyond150";
public const string PLUGIN_NAME = "Beyond 150";
public const string PLUGIN_VERSION = "1.0.2";
}
}