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.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using HarmonyLib; using Microsoft.CodeAnalysis; using R2API; using RoR2; using RoR2.Projectile; using RoR2.Skills; using UnityEngine; using UnityEngine.Rendering.PostProcessing; [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("AurelionRebalance")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.5.3.0")] [assembly: AssemblyInformationalVersion("1.5.3")] [assembly: AssemblyProduct("AurelionRebalance")] [assembly: AssemblyTitle("AurelionRebalance")] [assembly: AssemblyVersion("1.5.3.0")] [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 AurelionRebalance { internal static class AurelionRefs { internal static Assembly AurelionAsm; internal static Type TAurelion; internal static Type TPrefabs; internal static Type TPassive; internal static FieldInfo FCharacterPrefab; internal static FieldInfo FStardustBuff; internal static FieldInfo FOrbitalProjectile; internal static FieldInfo FNukeProjectile; internal static FieldInfo FSpecialOverride; internal static FieldInfo FMinSpecialRadius; internal static PropertyInfo PPassiveStarCount; internal static PropertyInfo PImpactEffect; internal static MethodInfo MTcdStatHook; internal static bool Ready { get; private set; } internal static GameObject CharacterPrefab => (GameObject)FCharacterPrefab.GetValue(null); internal static BuffDef StardustBuff => (BuffDef)FStardustBuff.GetValue(null); internal static GameObject OrbitalProjectile => (GameObject)FOrbitalProjectile.GetValue(null); internal static GameObject NukeProjectile => (GameObject)FNukeProjectile.GetValue(null); internal static GameObject ImpactEffect { get { object? obj = PImpactEffect?.GetValue(null); return (GameObject)((obj is GameObject) ? obj : null); } } internal static float StockMinSpecialRadius { get; private set; } = 12f; internal static void Resolve() { AurelionAsm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Aurelion"); if (AurelionAsm == null) { Plugin.Log.LogError((object)"Aurelion assembly not loaded - AurelionRebalance disabled."); return; } TAurelion = AurelionAsm.GetType("Aurelion.Aurelion", throwOnError: false); TPrefabs = AurelionAsm.GetType("Aurelion.Prefabs", throwOnError: false); TPassive = AurelionAsm.GetType("Aurelion.AurelionPassiveBehaviour", throwOnError: false); if (TAurelion == null || TPrefabs == null || TPassive == null) { Plugin.Log.LogError((object)$"Missing Aurelion types: Aurelion={TAurelion != null}, Prefabs={TPrefabs != null}, Passive={TPassive != null}."); return; } FCharacterPrefab = TAurelion.GetField("characterPrefab", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FStardustBuff = TPrefabs.GetField("stardust", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FOrbitalProjectile = TPrefabs.GetField("aurelionOrbitalProjectile", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FNukeProjectile = TPrefabs.GetField("aurelionNukeProjectile", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FSpecialOverride = TPassive.GetField("specialOverride", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FMinSpecialRadius = TPassive.GetField("minSpecialRadius", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); PPassiveStarCount = TPassive.GetProperty("starCount", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PImpactEffect = TPrefabs.GetProperty("aurelionOrbitalProjectileImpact", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (FCharacterPrefab == null || FStardustBuff == null || FOrbitalProjectile == null || FNukeProjectile == null || FSpecialOverride == null || FMinSpecialRadius == null || PPassiveStarCount == null) { Plugin.Log.LogError((object)"Failed to bind one or more Aurelion fields/properties - AurelionRebalance disabled."); return; } StockMinSpecialRadius = (float)FMinSpecialRadius.GetValue(null); Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "TrueCosmicDragon"); if (assembly != null) { MTcdStatHook = assembly.GetType("CenterOfTheUniverseUpgrade.CenterOfTheUniverseUpgradePlugin", throwOnError: false)?.GetMethod("OnGetStatCoefficients", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (MTcdStatHook == null) { Plugin.Log.LogWarning((object)"Could not find TrueCosmicDragon.OnGetStatCoefficients - Stardust stat override will be skipped."); } } else { Plugin.Log.LogWarning((object)"TrueCosmicDragon assembly not loaded - Stardust stat override will be skipped."); } Ready = true; } internal static int ReadStarCount(object collector) { if (collector == null) { return 0; } try { return (int)PPassiveStarCount.GetValue(collector); } catch { return 0; } } } internal static class CometDashPatch { private static readonly HashSet Dashing = new HashSet(); private static readonly FieldInfo FHealthComponent = AccessTools.Field(typeof(EntityState), "healthComponent"); internal static void Apply(Harmony h) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown Type type = AccessTools.TypeByName("Aurelion.AurelionUtility"); MethodInfo methodInfo = AccessTools.Method(type, "OnEnter", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(type, "OnExit", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(HealthComponent), "TakeDamage", new Type[1] { typeof(DamageInfo) }, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null) { Plugin.Log.LogError((object)$"Comet dash DR disabled (onEnter={methodInfo != null}, onExit={methodInfo2 != null}, TakeDamage={methodInfo3 != null})."); return; } h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CometDashPatch), "OnEnterPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); h.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(CometDashPatch), "OnExitPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); h.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(CometDashPatch), "TakeDamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)$"Comet of Legend dash damage reduction active ({RebalanceConfig.CometDamageReduction.Value:0.##} of incoming damage negated)."); } private static int Id(object stateInstance) { object? obj = FHealthComponent?.GetValue(stateInstance); HealthComponent val = (HealthComponent)((obj is HealthComponent) ? obj : null); if (val == null || !((Object)(object)val != (Object)null)) { return 0; } return ((Object)val).GetInstanceID(); } private static void OnEnterPostfix(object __instance) { int num = Id(__instance); if (num != 0) { Dashing.Add(num); } } private static void OnExitPostfix(object __instance) { int num = Id(__instance); if (num != 0) { Dashing.Remove(num); } } private static void TakeDamagePrefix(HealthComponent __instance, DamageInfo damageInfo) { if (!((Object)(object)__instance == (Object)null) && damageInfo != null && !(damageInfo.damage <= 0f)) { float value = RebalanceConfig.CometDamageReduction.Value; if (!(value <= 0f) && Dashing.Count != 0 && Dashing.Contains(((Object)__instance).GetInstanceID())) { damageInfo.damage *= Mathf.Clamp01(1f - value); } } } } internal static class DescriptionPatch { private static string D => ""; private static string U => ""; private static string E => ""; private static string Sub => ""; private static string CC => "Cosmic Creator"; private static string NL => "\r\n\r\n"; private static string NL1 => "\r\n"; private static int Pct(float f) { return Mathf.RoundToInt(f * 100f); } private static string ProcNote(float p) { return $"{Sub}(proc coefficient {p:0.##}){E}"; } internal static void Apply() { if (!RebalanceConfig.RewriteDescriptions.Value) { Plugin.Log.LogInfo((object)"Description rewrite disabled by config."); return; } int value = RebalanceConfig.RadiusStackCap.Value; string text = "The Skies Descend"; LanguageAPI.AddOverlay("AURELION_M2NEW_DESCRIPTION", "Aurelion Sol conjures a black hole, dragging enemies towards the centre and dealing " + D + "20% damage" + E + " every 0.25 seconds for 5 seconds, increased to 30% in the centre. Enemies that die in the black hole are counted as Aurelion Sol killing them." + NL + CC + "Enemies that die in the black hole grant 1 stardust each. The black hole's size increases with " + $"{U}stardust{E}{Sub} and caps at {value} {U}stardust{E}{Sub}."); LanguageAPI.AddOverlay("AURELION_M2_DESCRIPTION", "Aurelion Sol channels a newborn star which travels in the target direction. When recast or it strays more " + $"than {U}{RebalanceConfig.StarsurgeMaxDistance.Value:0.#} units{E}{Sub} from Aurelion Sol it detonates, " + $"{D}stunning{E} and dealing {D}{Pct(RebalanceConfig.StarsurgeBaseDamageCoefficient.Value)}%{E}, " + "increasing with distance travelled." + NL + CC + $"Damage with distance is increased, scaled to {D}{Pct(RebalanceConfig.StarsurgeBlastRadiusDamageMultiplier.Value)}%{E}{Sub}."); LanguageAPI.AddOverlay("AURELION_SPECNEW_DESCRIPTION", "Call down a star to impact the target location after 1.25 seconds, dealing " + $"{D}{Pct(RebalanceConfig.FallingStarDamageCoefficient.Value)}% damage{E} to enemies hit and " + D + "stunning" + E + " them for " + U + "1s" + E + ". " + ProcNote(RebalanceConfig.FallingStarProcCoefficient.Value) + NL + CC + "Falling Star grants 1 " + U + "stardust" + E + Sub + " for each enemy hit. Damage and effect radius increase with " + U + "stardust" + E + Sub + ", at 900 " + U + "stardust" + E + Sub + " this skill permanently becomes " + text); string text2 = "Aurelion Sol summons an enormous star to impact the target location after 2 seconds, dealing " + $"{D}{Pct(RebalanceConfig.SkiesDescendDamageCoefficient.Value)}% damage{E} to enemies hit and " + D + "stunning" + E + " them for " + U + "1s" + E + " " + ProcNote(RebalanceConfig.SkiesDescendProcCoefficient.Value) + ", upon impact, a massive shockwave rapidly expands through the map, dealing " + $"{D}{Pct(RebalanceConfig.ShockwaveDamageCoefficient.Value)}% damage{E} to anything caught and slowing them." + NL1 + CC + "Effect radius, shockwave travel distance and damage are all increased with " + U + "stardust" + E + Sub + "."; LanguageAPI.AddOverlay("AURELION_SPECNEW2_DESCRIPTION", text2); LanguageAPI.AddOverlay("AURELION_SPECNEW2_DESCRIPTION_KEYWORD", text + text2); LanguageAPI.AddOverlay("AURELION_UTIL_DESCRIPTION", $"Aurelion Sol flies in a burst of speed in the direction aimed at {U}{RebalanceConfig.CometSpeedMultiplier.Value:0.##}x{E}{Sub} " + "the base speed, further scaling with " + U + "movement speed" + E + Sub + ", and takes " + $"{D}{Pct(RebalanceConfig.CometDamageReduction.Value)}% less damage{E}{Sub} while dashing. " + "If Starsurge is currently active or is cast during Comet of Legend, it will center itself on Aurelion Sol " + $"while he travels and grows at {U}{Pct(RebalanceConfig.StarsurgeCometGrowthMultiplier.Value)}%{E}{Sub} of its usual rate. " + "Can be cancelled at any time by pressing Jump." + NL + CC + "Maximum travel distance is increased further with " + U + "stardust" + E + Sub + "."); LanguageAPI.AddOverlay("AURELION_PASSIVE2_DESCRIPTION", "Aurelion Sol can fly at will and his abilities break his foes down to " + U + "stardust" + E + Sub + ". Each " + U + "stardust" + E + Sub + " stack empowers his abilities and, via True Cosmic Dragon" + E + ", his stats: " + StatSummary() + ". Skill effect radii also grow per stack (see each skill)." + NL + CC); Plugin.Log.LogInfo((object)"Skill descriptions rewritten to match config."); } private static string StatSummary() { List parts = new List(); Add(RebalanceConfig.HealthPerStack.Value, "health"); Add(RebalanceConfig.RegenPerStack.Value, "regen"); Add(RebalanceConfig.DamagePerStack.Value, "damage"); Add(RebalanceConfig.AttackSpeedPerStack.Value, "attack speed"); Add(RebalanceConfig.MoveSpeedPerStack.Value, "move speed"); Add(RebalanceConfig.CritPerStack.Value, "crit"); Add(RebalanceConfig.AccelerationPerStack.Value, "acceleration"); parts.Add("scaling armor"); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < parts.Count; i++) { if (i > 0) { stringBuilder.Append((i == parts.Count - 1) ? " and " : ", "); } stringBuilder.Append(parts[i]); } stringBuilder.Append(" per stack"); return stringBuilder.ToString(); void Add(float perStack, string label) { if (perStack > 0f) { parts.Add($"+{perStack * 100f:0.###}% {label}"); } } } } internal static class ImpactVfxPatch { internal static void Apply() { GameObject impactEffect = AurelionRefs.ImpactEffect; if ((Object)(object)impactEffect == (Object)null) { Plugin.Log.LogWarning((object)"Impact VFX prefab not found - flash unchanged."); return; } float num = Mathf.Clamp01(RebalanceConfig.ImpactFlashWeight.Value); PostProcessVolume componentInChildren = impactEffect.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.weight = num; if (num <= 0f) { ((Behaviour)componentInChildren).enabled = false; } Plugin.Log.LogInfo((object)$"Falling Star / The Skies Descend impact flash weight -> {num:0.##}."); } else { Plugin.Log.LogWarning((object)"Impact VFX has no PostProcessVolume - screen flash unchanged."); } float num2 = Mathf.Max(0f, RebalanceConfig.ImpactLightMultiplier.Value); if (!Mathf.Approximately(num2, 1f)) { Light componentInChildren2 = impactEffect.GetComponentInChildren(true); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.intensity *= num2; Plugin.Log.LogInfo((object)$"Impact flash light intensity x{num2:0.##} -> {componentInChildren2.intensity:0.##}."); } } } } internal static class SkillTuningPatch { internal static void ApplyStatic(Harmony h) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName("Aurelion.AurelionNewSpecialCast"), "OnEnter", (Type[])null, (Type[])null); if (methodInfo != null) { h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(SkillTuningPatch), "ImpactDamageTranspiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } else { Plugin.Log.LogError((object)"AurelionNewSpecialCast.OnEnter not found - Falling Star / Skies Descend impact damage unchanged."); } MethodInfo methodInfo2 = AccessTools.Method(AccessTools.TypeByName("Aurelion.CometImpact"), "Search", (Type[])null, (Type[])null); if (methodInfo2 != null) { h.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(SkillTuningPatch), "ShockwaveDamageTranspiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } else { Plugin.Log.LogError((object)"CometImpact.Search not found - Skies Descend shockwave damage unchanged."); } MethodInfo methodInfo3 = AccessTools.Method(AurelionRefs.TAurelion, "HealthComponent_TakeDamage", (Type[])null, (Type[])null); if (methodInfo3 != null) { h.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(SkillTuningPatch), "BreathBurstTranspiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } else { Plugin.Log.LogError((object)"Aurelion.HealthComponent_TakeDamage not found - Breath of Light burst Stardust scaling unchanged."); } MethodInfo methodInfo4 = AccessTools.Method(AccessTools.TypeByName("Aurelion.AurelionPrimary"), "OnEnter", (Type[])null, (Type[])null); if (methodInfo4 != null) { h.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(SkillTuningPatch), "SolarFlareTranspiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } else { Plugin.Log.LogError((object)"AurelionPrimary.OnEnter not found - Solar Flare Stardust attack-speed unchanged."); } } internal static float FallingStarMult() { return RebalanceConfig.FallingStarDamageCoefficient.Value; } internal static float SkiesDescendMult() { return RebalanceConfig.SkiesDescendDamageCoefficient.Value; } internal static float ShockwaveMult() { return RebalanceConfig.ShockwaveDamageCoefficient.Value; } internal static float ShockwaveStardustRate() { return 0.05f * RebalanceConfig.ShockwaveStardustDamageMultiplier.Value; } internal static float BreathBurstStardustRate() { return 0.01f * RebalanceConfig.BreathOfLightBurstStardustMultiplier.Value; } internal static float SolarFlareStardustRate() { return 0.005f * RebalanceConfig.SolarFlareStardustAttackSpeedMultiplier.Value; } private static bool SwapStarCountLiteral(List code, float stockLiteral, MethodInfo replacement) { int num = code.FindIndex((CodeInstruction c) => (c.opcode == OpCodes.Callvirt || c.opcode == OpCodes.Call) && c.operand is MethodBase methodBase && methodBase.Name == "get_starCount"); if (num < 0) { return false; } for (int num2 = num + 1; num2 < code.Count && num2 < num + 6; num2++) { if (code[num2].opcode == OpCodes.Ldc_R4 && code[num2].operand is float num3 && Mathf.Approximately(num3, stockLiteral)) { code[num2].opcode = OpCodes.Call; code[num2].operand = replacement; return true; } } return false; } private static IEnumerable BreathBurstTranspiler(IEnumerable instructions) { List list = new List(instructions); if (SwapStarCountLiteral(list, 0.01f, AccessTools.Method(typeof(SkillTuningPatch), "BreathBurstStardustRate", (Type[])null, (Type[])null))) { Plugin.Log.LogInfo((object)"Breath of Light burst Stardust scaling patched."); return list; } Plugin.Log.LogWarning((object)"Breath of Light burst Stardust scaling: 0.01 literal not found in HealthComponent_TakeDamage - unchanged."); return list; } private static IEnumerable SolarFlareTranspiler(IEnumerable instructions) { List list = new List(instructions); if (SwapStarCountLiteral(list, 0.005f, AccessTools.Method(typeof(SkillTuningPatch), "SolarFlareStardustRate", (Type[])null, (Type[])null))) { Plugin.Log.LogInfo((object)"Solar Flare Stardust attack-speed patched."); return list; } Plugin.Log.LogWarning((object)"Solar Flare Stardust attack-speed: 0.005 literal not found in AurelionPrimary.OnEnter - unchanged."); return list; } private static IEnumerable ImpactDamageTranspiler(IEnumerable instructions) { List list = new List(instructions); MethodInfo operand = AccessTools.Method(typeof(SkillTuningPatch), "FallingStarMult", (Type[])null, (Type[])null); MethodInfo operand2 = AccessTools.Method(typeof(SkillTuningPatch), "SkiesDescendMult", (Type[])null, (Type[])null); int num = list.FindIndex((CodeInstruction c) => c.opcode == OpCodes.Ldc_I4_S && c.operand is sbyte b && b == 30); int num2 = ((num < 0) ? (-1) : list.FindLastIndex(num, (CodeInstruction c) => c.opcode == OpCodes.Ldc_I4_5)); if (num >= 0 && num2 >= 0) { list[num2].opcode = OpCodes.Call; list[num2].operand = operand; list[num].opcode = OpCodes.Call; list[num].operand = operand2; Plugin.Log.LogInfo((object)"Falling Star / The Skies Descend impact damage coefficients patched."); } else { Plugin.Log.LogWarning((object)$"Impact-damage transpiler could not locate the 5/30 literal pair in AurelionNewSpecialCast.OnEnter (i5={num2}, i30={num}) - Aurelion.dll may have changed; impact damage unchanged."); } return list; } private static IEnumerable ShockwaveDamageTranspiler(IEnumerable instructions) { List list = new List(instructions); int num = list.FindIndex((CodeInstruction c) => c.opcode == OpCodes.Ldc_R4 && c.operand is float num2 && Mathf.Approximately(num2, 18f)); bool flag = num >= 0; if (flag) { list[num].opcode = OpCodes.Call; list[num].operand = AccessTools.Method(typeof(SkillTuningPatch), "ShockwaveMult", (Type[])null, (Type[])null); } bool flag2 = SwapStarCountLiteral(list, 0.05f, AccessTools.Method(typeof(SkillTuningPatch), "ShockwaveStardustRate", (Type[])null, (Type[])null)); if (flag && flag2) { Plugin.Log.LogInfo((object)"The Skies Descend shockwave damage (base + Stardust) patched."); } else { Plugin.Log.LogWarning((object)$"Shockwave-damage transpiler incomplete (base={flag}, stardust={flag2}) - CometImpact.Search may have changed."); } return list; } internal static void ApplyContent() { GameObject characterPrefab = AurelionRefs.CharacterPrefab; if ((Object)(object)characterPrefab == (Object)null) { Plugin.Log.LogError((object)"Aurelion characterPrefab is null - cooldown patch skipped."); return; } SkillLocator component = characterPrefab.GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogError((object)"Aurelion characterPrefab has no SkillLocator - cooldown patch skipped."); return; } SetRecharge(component.secondary, "AURELION_M2NEW", RebalanceConfig.SingularityCooldown.Value, "Singularity"); SetRecharge(component.special, "AURELION_SPECNEW", RebalanceConfig.FallingStarCooldown.Value, "Falling Star"); object? value = AurelionRefs.FSpecialOverride.GetValue(null); SkillDef val = (SkillDef)((value is SkillDef) ? value : null); if ((Object)(object)val != (Object)null) { val.baseRechargeInterval = RebalanceConfig.SkiesDescendCooldown.Value; Plugin.Log.LogInfo((object)$"The Skies Descend cooldown -> {val.baseRechargeInterval}s."); } else { Plugin.Log.LogError((object)"AurelionPassiveBehaviour.specialOverride is null - Skies Descend cooldown unchanged."); } SetProc(AurelionRefs.OrbitalProjectile, RebalanceConfig.FallingStarProcCoefficient.Value, "Falling Star"); SetProc(AurelionRefs.NukeProjectile, RebalanceConfig.SkiesDescendProcCoefficient.Value, "The Skies Descend"); } private static void SetRecharge(GenericSkill slot, string skillName, float seconds, string label) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (((slot == null) ? null : slot.skillFamily?.variants) == null) { Plugin.Log.LogError((object)(label + ": skill slot/family missing.")); return; } Variant[] variants = slot.skillFamily.variants; foreach (Variant val in variants) { if ((Object)(object)val.skillDef != (Object)null && val.skillDef.skillName == skillName) { val.skillDef.baseRechargeInterval = seconds; Plugin.Log.LogInfo((object)$"{label} cooldown -> {seconds}s."); return; } } Plugin.Log.LogError((object)(label + ": variant '" + skillName + "' not found in family.")); } private static void SetProc(GameObject projectilePrefab, float proc, string label) { if ((Object)(object)projectilePrefab == (Object)null) { Plugin.Log.LogError((object)(label + ": projectile prefab null - proc unchanged.")); return; } ProjectileController component = projectilePrefab.GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogError((object)(label + ": projectile prefab has no ProjectileController.")); return; } component.procCoefficient = proc; Plugin.Log.LogInfo((object)$"{label} impact proc coefficient -> {proc}."); } } internal static class StardustRadiusPatch { private const float SingularityBase = 10f; private const float ShockwaveInnerToOuter = 2.5f; private static readonly FieldInfo FCometEnlargeImpact = Fld("Aurelion.CometEnlarge", "impact"); private static readonly FieldInfo FCometEnlargeCollector = Fld("Aurelion.CometEnlarge", "collector"); private static readonly FieldInfo FCometImpactCollector = Fld("Aurelion.CometImpact", "collector"); private static readonly FieldInfo FCometImpactSearch = Fld("Aurelion.CometImpact", "search"); private static readonly FieldInfo FCometImpactMaxRadius = Fld("Aurelion.CometImpact", "maxRadius"); private static readonly FieldInfo FGravExplosion = Fld("Aurelion.AurelionGravSphereBehaviour", "explosion"); private static readonly FieldInfo FGravRadialForce = Fld("Aurelion.AurelionGravSphereBehaviour", "radialForce"); private static readonly FieldInfo FGravCollector = Fld("Aurelion.AurelionGravSphereBehaviour", "collector"); private static readonly FieldInfo FNewSpecialIndicator = Fld("Aurelion.AurelionNewSpecial", "areaIndicator"); private static readonly FieldInfo FNewSecondaryIndicator = Fld("Aurelion.AurelionNewSecondary", "areaIndicator"); private static bool _loggedGrav; private static float StockBase => AurelionRefs.StockMinSpecialRadius; internal static void Apply(Harmony h) { Hook(h, "Aurelion.CometEnlarge", "Start", "CometEnlarge_Start"); Hook(h, "Aurelion.CometImpact", "Start", "CometImpact_Start"); Hook(h, "Aurelion.AurelionGravSphereBehaviour", "Start", "GravSphere_Start"); Hook(h, "Aurelion.AurelionNewSpecial", "OnEnter", "NewSpecial_OnEnter"); Hook(h, "Aurelion.AurelionNewSecondary", "OnEnter", "NewSecondary_OnEnter"); Plugin.Log.LogInfo((object)($"Radius patch active (Falling Star/Skies base x{RebalanceConfig.SpecialBaseRadiusMultiplier.Value}, " + $"{RebalanceConfig.RadiusGrowthPerStack.Value}/stack; Singularity {RebalanceConfig.SingularityRadiusGrowthPerStack.Value}/stack; " + $"cap {RebalanceConfig.RadiusStackCap.Value}, post-cap x{RebalanceConfig.PostCapRadiusMultiplier.Value}; " + $"shockwave x{RebalanceConfig.ShockwaveRadiusMultiplier.Value}).")); } private static void Hook(Harmony h, string typeName, string method, string postfix) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown Type type = AccessTools.TypeByName(typeName); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, method, (Type[])null, (Type[])null)); if (methodInfo == null) { Plugin.Log.LogError((object)("Radius patch: " + typeName + "." + method + " not found.")); } else { h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(StardustRadiusPatch), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static float Bonus(int starCount, float perStack, bool hardCap) { int num = Mathf.Max(0, RebalanceConfig.RadiusStackCap.Value); int num2 = Mathf.Min(starCount, num); int num3 = Mathf.Max(0, starCount - num); float num4 = (hardCap ? 0f : Mathf.Max(0f, RebalanceConfig.PostCapRadiusMultiplier.Value)); return (float)num2 * perStack + (float)num3 * perStack * num4; } private static float SpecialImpactRadius(int sc) { return StockBase * RebalanceConfig.SpecialBaseRadiusMultiplier.Value + Bonus(sc, RebalanceConfig.RadiusGrowthPerStack.Value, hardCap: false); } private static int StarCount(object instance, FieldInfo collectorField) { return AurelionRefs.ReadStarCount(collectorField?.GetValue(instance)); } private static FieldInfo Fld(string typeName, string field) { Type type = AccessTools.TypeByName(typeName); FieldInfo fieldInfo = ((type == null) ? null : AccessTools.Field(type, field)); if (fieldInfo == null) { Plugin.Log.LogError((object)("Radius patch: field " + typeName + "." + field + " not found.")); } return fieldInfo; } private static void CometEnlarge_Start(object __instance) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) object? obj = FCometEnlargeImpact?.GetValue(__instance); ProjectileExplosion val = (ProjectileExplosion)((obj is ProjectileExplosion) ? obj : null); if (val != null) { float num = (val.blastRadius = SpecialImpactRadius(StarCount(__instance, FCometEnlargeCollector))); ((Component)((__instance is Component) ? __instance : null)).transform.localScale = Vector3.one * num; } } private static void CometImpact_Start(object __instance) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) int starCount = StarCount(__instance, FCometImpactCollector); float num = Mathf.Max(0f, RebalanceConfig.ShockwaveRadiusMultiplier.Value); float num2 = (StockBase + Bonus(starCount, RebalanceConfig.RadiusGrowthPerStack.Value, hardCap: false)) * num; float num3 = 2.5f * (StockBase + Bonus(starCount, RebalanceConfig.ShockwaveMaxGrowthPerStack.Value, hardCap: false)) * num; FCometImpactMaxRadius?.SetValue(__instance, num3); object? obj = FCometImpactSearch?.GetValue(__instance); SphereSearch val = (SphereSearch)((obj is SphereSearch) ? obj : null); if (val != null) { val.radius = num2; ((Component)((__instance is Component) ? __instance : null)).transform.localScale = Vector3.one * num2; } } private static void GravSphere_Start(object __instance) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) object? obj = FGravExplosion?.GetValue(__instance); ProjectileExplosion val = (ProjectileExplosion)((obj is ProjectileExplosion) ? obj : null); if (val != null) { int num = StarCount(__instance, FGravCollector); float num2 = (val.blastRadius = 10f + Bonus(num, RebalanceConfig.SingularityRadiusGrowthPerStack.Value, hardCap: true)); object? obj2 = FGravRadialForce?.GetValue(__instance); RadialForce val2 = (RadialForce)((obj2 is RadialForce) ? obj2 : null); if (val2 != null) { val2.radius = num2; } ((Component)((__instance is Component) ? __instance : null)).transform.localScale = Vector3.one * num2; if (!_loggedGrav) { _loggedGrav = true; Plugin.Log.LogInfo((object)($"Singularity radius: starCount={num}, cap={RebalanceConfig.RadiusStackCap.Value}, " + $"perStack={RebalanceConfig.SingularityRadiusGrowthPerStack.Value} -> radius {num2:0.##} (stock would be {10f + (float)num * 0.05f:0.##}).")); } } } private static void NewSpecial_OnEnter(object __instance) { object collector = BehaviourField(__instance.GetType())?.GetValue(__instance); SetIndicator(__instance, FNewSpecialIndicator, SpecialImpactRadius(AurelionRefs.ReadStarCount(collector))); } private static void NewSecondary_OnEnter(object __instance) { object collector = BehaviourField(__instance.GetType())?.GetValue(__instance); float radius = 10f + Bonus(AurelionRefs.ReadStarCount(collector), RebalanceConfig.SingularityRadiusGrowthPerStack.Value, hardCap: true); SetIndicator(__instance, FNewSecondaryIndicator, radius); } private static void SetIndicator(object stateInstance, FieldInfo indicatorField, float radius) { //IL_0025: 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) object? obj = indicatorField?.GetValue(stateInstance); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (val != null && (Object)(object)val != (Object)null) { val.transform.localScale = Vector3.one * Mathf.Max(0f, radius); } } private static FieldInfo BehaviourField(Type stateType) { return AccessTools.Field(stateType, "behaviour"); } } internal static class StardustStatsPatch { private static readonly FieldInfo AccelBackingField = typeof(CharacterBody).GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); internal static void Apply(Harmony h) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown if (!RebalanceConfig.EnableStatOverride.Value) { Plugin.Log.LogInfo((object)"Stardust stat override disabled by config - True Cosmic Dragon's handler runs unchanged."); return; } if (AurelionRefs.MTcdStatHook == null) { Plugin.Log.LogWarning((object)"Skipping Stardust stat override (TCD hook not resolved)."); return; } h.Patch((MethodBase)AurelionRefs.MTcdStatHook, new HarmonyMethod(typeof(StardustStatsPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)($"Stardust stat override active (moveSpeed/stack={RebalanceConfig.MoveSpeedPerStack.Value}, " + $"accel/stack={RebalanceConfig.AccelerationPerStack.Value}, crit/stack={RebalanceConfig.CritPerStack.Value}).")); } private static bool Prefix(CharacterBody sender, StatHookEventArgs args) { if ((Object)(object)sender == (Object)null) { return false; } BuffDef stardustBuff = AurelionRefs.StardustBuff; if ((Object)(object)stardustBuff == (Object)null) { return false; } int buffCount = sender.GetBuffCount(stardustBuff); if (buffCount <= 0) { return false; } float num = buffCount; args.healthMultAdd += RebalanceConfig.HealthPerStack.Value * num; args.regenMultAdd += RebalanceConfig.RegenPerStack.Value * num; args.damageMultAdd += RebalanceConfig.DamagePerStack.Value * num; args.attackSpeedMultAdd += RebalanceConfig.AttackSpeedPerStack.Value * num; args.moveSpeedMultAdd += RebalanceConfig.MoveSpeedPerStack.Value * num; args.critAdd += RebalanceConfig.CritPerStack.Value * num; float num2 = Mathf.Log(1f + RebalanceConfig.ArmorLogInner.Value * num) * RebalanceConfig.ArmorLogOuter.Value; if (num2 < 1f) { args.armorAdd += 100f * num2 / (1f - num2); } float value = RebalanceConfig.AccelerationPerStack.Value; if (value > 0f) { float num3 = (sender.baseAcceleration = 14f * (1f + value * num)); AccelBackingField?.SetValue(sender, num3); } sender.sprintingSpeedMultiplier = RebalanceConfig.SprintMultiplier.Value; return false; } } internal static class StarsurgeCometPatch { private static readonly FieldInfo FSpeedMultiplier = FieldOf("Aurelion.AurelionSecondaryBehaviour", "speedMultiplier"); private static readonly FieldInfo FUtilController = FieldOf("Aurelion.AurelionUtility", "controller"); private static readonly FieldInfo FCtrlBehaviour = FieldOf("Aurelion.AurelionSecondaryController", "behaviour"); internal static float BaseDamage() { return RebalanceConfig.StarsurgeBaseDamageCoefficient.Value; } internal static float GrowthRate() { return RebalanceConfig.StarsurgeGrowthPerSecond.Value; } internal static float StardustPerStack() { return RebalanceConfig.StarsurgeStardustDamagePerStack.Value; } internal static float BlastRadiusDamageMult() { return RebalanceConfig.StarsurgeBlastRadiusDamageMultiplier.Value; } internal static float MaxDistance() { return RebalanceConfig.StarsurgeMaxDistance.Value; } internal static float CometSpeed() { return RebalanceConfig.CometSpeedMultiplier.Value; } internal static void ApplyStatic(Harmony h) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown Type type = AccessTools.TypeByName("Aurelion.AurelionSecondaryBehaviour"); Type type2 = AccessTools.TypeByName("Aurelion.AurelionSecondaryController"); Type type3 = AccessTools.TypeByName("Aurelion.AurelionSecondary"); Type type4 = AccessTools.TypeByName("Aurelion.AurelionUtility"); Patch(h, AccessTools.DeclaredConstructor(type, Type.EmptyTypes, false), "CtorTranspiler", "AurelionSecondaryBehaviour..ctor"); Patch(h, AccessTools.Method(type3, "Fire", (Type[])null, (Type[])null), "FireTranspiler", "AurelionSecondary.Fire"); Patch(h, AccessTools.Method(type, "FixedUpdate", (Type[])null, (Type[])null), "BehaviourFixedUpdateTranspiler", "AurelionSecondaryBehaviour.FixedUpdate"); Patch(h, AccessTools.Method(type2, "Detonate", (Type[])null, (Type[])null), "DetonateTranspiler", "AurelionSecondaryController.Detonate"); Patch(h, AccessTools.Method(type4, "FixedUpdate", (Type[])null, (Type[])null), "CometFixedUpdateTranspiler", "AurelionUtility.FixedUpdate"); MethodInfo methodInfo = AccessTools.Method(type, "UpdateSpeedMult", (Type[])null, (Type[])null); if (methodInfo != null) { h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(StarsurgeCometPatch), "UpdateSpeedMultPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Plugin.Log.LogError((object)"AurelionSecondaryBehaviour.UpdateSpeedMult not found - Comet star-growth multiplier unchanged."); } MethodInfo methodInfo2 = AccessTools.Method(type4, "OnExit", (Type[])null, (Type[])null); if (methodInfo2 != null) { h.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(StarsurgeCometPatch), "CometOnExitPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Plugin.Log.LogError((object)"AurelionUtility.OnExit not found - Starsurge growth will stay stuck after a dash."); } Plugin.Log.LogInfo((object)($"Starsurge/Comet patch active (base {BaseDamage()}x, growth {GrowthRate()}/s, comet growth x{RebalanceConfig.StarsurgeCometGrowthMultiplier.Value}, " + $"blast-radius dmg x{BlastRadiusDamageMult()}, leash {MaxDistance()}, comet speed x{CometSpeed()}).")); } private static void Patch(Harmony h, MethodBase target, string transpiler, string label) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown if (target == null) { Plugin.Log.LogError((object)("Starsurge/Comet: " + label + " not found - skipped.")); } else { h.Patch(target, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(StarsurgeCometPatch), transpiler, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } } private static FieldInfo FieldOf(string typeName, string field) { Type type = AccessTools.TypeByName(typeName); FieldInfo fieldInfo = ((type == null) ? null : AccessTools.Field(type, field)); if (fieldInfo == null) { Plugin.Log.LogError((object)("Starsurge/Comet: field " + typeName + "." + field + " not found.")); } return fieldInfo; } private static IEnumerable CtorTranspiler(IEnumerable instructions) { List list = new List(instructions); int num = SwapFirstLdcR4(list, 2.5f, "GrowthRate"); Log(num == 1, "Starsurge base growth rate", num); return list; } private static IEnumerable FireTranspiler(IEnumerable instructions) { List list = new List(instructions); int num = SwapLdcR4AfterCall(list, "get_damage", 4f, "BaseDamage"); Log(num == 1, "Starsurge base damage coefficient", num); return list; } private static IEnumerable BehaviourFixedUpdateTranspiler(IEnumerable instructions) { List list = new List(instructions); int num = SwapLdcR4AfterCall(list, "Distance", 13f, "MaxDistance"); int num2 = SwapLdcR4AfterCall(list, "get_starCount", 0.005f, "StardustPerStack"); int num3 = InjectAfterDivBy10(list, "BlastRadiusDamageMult"); Log(num == 1 && num3 == 1, "Starsurge FixedUpdate (leash / stardust / blast-radius dmg)", num + num2 * 10 + num3 * 100); return list; } private static IEnumerable DetonateTranspiler(IEnumerable instructions) { List list = new List(instructions); int num = InjectAfterDivBy10(list, "BlastRadiusDamageMult"); Log(num == 1, "Starsurge Detonate blast-radius damage multiplier", num); return list; } private static IEnumerable CometFixedUpdateTranspiler(IEnumerable instructions) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown List list = new List(instructions); int num = list.FindIndex((CodeInstruction c) => c.opcode == OpCodes.Ldfld && c.operand is FieldInfo fieldInfo && fieldInfo.Name == "speedCoefficient"); int num2 = 0; if (num >= 0 && num + 3 < list.Count && list[num + 1].opcode == OpCodes.Mul && list[num + 3].opcode == OpCodes.Mul) { list.InsertRange(num + 4, (IEnumerable)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(StarsurgeCometPatch), "CometSpeed", (Type[])null, (Type[])null)), new CodeInstruction(OpCodes.Mul, (object)null) }); num2 = 1; } Log(num2 == 1, "Comet of Legend movement speed", num2); return list; } private static void UpdateSpeedMultPostfix(object __instance) { if (!(FSpeedMultiplier == null)) { float value = RebalanceConfig.StarsurgeCometGrowthMultiplier.Value; FSpeedMultiplier.SetValue(__instance, (float)FSpeedMultiplier.GetValue(__instance) * value); } } private static void CometOnExitPostfix(object __instance) { if (FUtilController == null || FCtrlBehaviour == null || FSpeedMultiplier == null) { return; } object value = FUtilController.GetValue(__instance); if (value != null) { object value2 = FCtrlBehaviour.GetValue(value); if (value2 != null) { FSpeedMultiplier.SetValue(value2, GrowthRate()); } } } private static int SwapFirstLdcR4(List code, float literal, string getter) { MethodInfo operand = AccessTools.Method(typeof(StarsurgeCometPatch), getter, (Type[])null, (Type[])null); int num = 0; for (int i = 0; i < code.Count; i++) { if (code[i].opcode == OpCodes.Ldc_R4 && code[i].operand is float num2 && Mathf.Approximately(num2, literal)) { code[i].opcode = OpCodes.Call; code[i].operand = operand; num++; } } return num; } private static int SwapLdcR4AfterCall(List code, string calleeName, float literal, string getter) { MethodInfo operand = AccessTools.Method(typeof(StarsurgeCometPatch), getter, (Type[])null, (Type[])null); int num = code.FindIndex((CodeInstruction c) => (c.opcode == OpCodes.Call || c.opcode == OpCodes.Callvirt) && c.operand is MethodBase methodBase && methodBase.Name == calleeName); if (num < 0) { return 0; } for (int num2 = num + 1; num2 < code.Count && num2 <= num + 6; num2++) { if (code[num2].opcode == OpCodes.Ldc_R4 && code[num2].operand is float num3 && Mathf.Approximately(num3, literal)) { code[num2].opcode = OpCodes.Call; code[num2].operand = operand; return 1; } } return 0; } private static int InjectAfterDivBy10(List code, string getter) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown for (int i = 0; i < code.Count - 1; i++) { if (code[i].opcode == OpCodes.Ldc_R4 && code[i].operand is float num && Mathf.Approximately(num, 10f) && code[i + 1].opcode == OpCodes.Div) { code.InsertRange(i + 2, (IEnumerable)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(StarsurgeCometPatch), getter, (Type[])null, (Type[])null)), new CodeInstruction(OpCodes.Mul, (object)null) }); return 1; } } return 0; } private static void Log(bool ok, string what, int code) { if (ok) { Plugin.Log.LogInfo((object)(what + " patched.")); } else { Plugin.Log.LogWarning((object)$"{what}: IL anchor not found (code {code}) - Aurelion.dll may have changed; unchanged."); } } } [BepInPlugin("com.local.aurelionrebalance", "AurelionRebalance", "1.5.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.local.aurelionrebalance"; public const string AurelionGuid = "com.Dragonyck.AurelionSol"; public const string TrueCosmicDragonGuid = "com.phong.aurelionsol.truecosmicdragon"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; RebalanceConfig.Bind(((BaseUnityPlugin)this).Config); AurelionRefs.Resolve(); if (!AurelionRefs.Ready) { Log.LogError((object)"AurelionRebalance could not bind AurelionSol - no changes applied."); return; } _harmony = new Harmony("com.local.aurelionrebalance"); SkillTuningPatch.ApplyStatic(_harmony); StardustStatsPatch.Apply(_harmony); StardustRadiusPatch.Apply(_harmony); StarsurgeCometPatch.ApplyStatic(_harmony); CometDashPatch.Apply(_harmony); SkillTuningPatch.ApplyContent(); ImpactVfxPatch.Apply(); DescriptionPatch.Apply(); Log.LogInfo((object)"AurelionRebalance 1.5.3 applied."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class RebalanceConfig { internal static ConfigEntry EnableStatOverride; internal static ConfigEntry HealthPerStack; internal static ConfigEntry RegenPerStack; internal static ConfigEntry DamagePerStack; internal static ConfigEntry MoveSpeedPerStack; internal static ConfigEntry AttackSpeedPerStack; internal static ConfigEntry CritPerStack; internal static ConfigEntry AccelerationPerStack; internal static ConfigEntry ArmorLogInner; internal static ConfigEntry ArmorLogOuter; internal static ConfigEntry SprintMultiplier; internal static ConfigEntry SpecialBaseRadiusMultiplier; internal static ConfigEntry RadiusGrowthPerStack; internal static ConfigEntry SingularityRadiusGrowthPerStack; internal static ConfigEntry RadiusStackCap; internal static ConfigEntry PostCapRadiusMultiplier; internal static ConfigEntry SingularityCooldown; internal static ConfigEntry FallingStarCooldown; internal static ConfigEntry SkiesDescendCooldown; internal static ConfigEntry FallingStarDamageCoefficient; internal static ConfigEntry SkiesDescendDamageCoefficient; internal static ConfigEntry FallingStarProcCoefficient; internal static ConfigEntry SkiesDescendProcCoefficient; internal static ConfigEntry ShockwaveRadiusMultiplier; internal static ConfigEntry ShockwaveMaxGrowthPerStack; internal static ConfigEntry ShockwaveDamageCoefficient; internal static ConfigEntry RewriteDescriptions; internal static ConfigEntry ImpactFlashWeight; internal static ConfigEntry ImpactLightMultiplier; internal static ConfigEntry ShockwaveStardustDamageMultiplier; internal static ConfigEntry BreathOfLightBurstStardustMultiplier; internal static ConfigEntry SolarFlareStardustAttackSpeedMultiplier; internal static ConfigEntry StarsurgeBaseDamageCoefficient; internal static ConfigEntry StarsurgeGrowthPerSecond; internal static ConfigEntry StarsurgeCometGrowthMultiplier; internal static ConfigEntry StarsurgeStardustDamagePerStack; internal static ConfigEntry StarsurgeBlastRadiusDamageMultiplier; internal static ConfigEntry StarsurgeMaxDistance; internal static ConfigEntry CometSpeedMultiplier; internal static ConfigEntry CometDamageReduction; internal static void Bind(ConfigFile cfg) { EnableStatOverride = cfg.Bind("1. Stardust Passive", "EnableStatOverride", true, "Master switch. When true this mod replaces True Cosmic Dragon's Stardust RecalculateStats handler with the per-stack values below. When false, TCD's original handler runs untouched."); HealthPerStack = cfg.Bind("1. Stardust Passive", "HealthPerStack", 0.005f, "Max health multiplier added per Stardust stack. (TCD 0.2.0: 0.005)"); RegenPerStack = cfg.Bind("1. Stardust Passive", "RegenPerStack", 0f, "Regen multiplier added per Stardust stack. (TCD 0.2.0: 0.0)"); DamagePerStack = cfg.Bind("1. Stardust Passive", "DamagePerStack", 0f, "Damage multiplier added per Stardust stack. (TCD 0.2.0: 0.0)"); MoveSpeedPerStack = cfg.Bind("1. Stardust Passive", "MoveSpeedPerStack", 0f, "Move speed multiplier added per Stardust stack. 0 = removed. (TCD 0.2.0: 0.001)"); AttackSpeedPerStack = cfg.Bind("1. Stardust Passive", "AttackSpeedPerStack", 0f, "Attack speed multiplier added per Stardust stack. (TCD 0.2.0: 0.0)"); CritPerStack = cfg.Bind("1. Stardust Passive", "CritPerStack", 0f, "Crit chance added per Stardust stack. 0 = removed. (TCD 0.2.0: 0.01)"); AccelerationPerStack = cfg.Bind("1. Stardust Passive", "AccelerationPerStack", 0f, "Acceleration bonus per Stardust stack: acceleration = 14 * (1 + value * stacks). 0 = acceleration left at the body base of 14. (TCD 0.2.0: 0.01)"); ArmorLogInner = cfg.Bind("1. Stardust Passive", "ArmorLogInner", 0f, "Inner coefficient of the logarithmic Stardust armor bonus: Mathf.Log(1 + inner * stacks). (TCD 0.2.0: 0.08)"); ArmorLogOuter = cfg.Bind("1. Stardust Passive", "ArmorLogOuter", 0f, "Outer coefficient of the logarithmic Stardust armor bonus. (TCD 0.2.0: 0.0)"); SprintMultiplier = cfg.Bind("1. Stardust Passive", "SprintMultiplier", 1f, "Sprint speed multiplier forced while any Stardust stack is held. (TCD 0.2.0 and body base: 1.)"); SpecialBaseRadiusMultiplier = cfg.Bind("2. Skill Effect Radius", "SpecialBaseRadiusMultiplier", 1.3f, "Multiplier on the base impact radius of Falling Star and The Skies Descend (stock base 12). 1.3 = +30%. Does NOT affect Singularity or the Skies Descend shockwave."); RadiusGrowthPerStack = cfg.Bind("2. Skill Effect Radius", "RadiusGrowthPerStack", 0.025f, "Effect radius added per Stardust stack for Falling Star, the Skies Descend impact indicator and the shockwave's inner search radius. (Default: 0.025)"); SingularityRadiusGrowthPerStack = cfg.Bind("2. Skill Effect Radius", "SingularityRadiusGrowthPerStack", 0.05f, "Singularity black-hole radius (pull + damage + visual) added per Stardust stack, separate from RadiusGrowthPerStack. Still hard-capped at RadiusStackCap. Stock game: 0.05."); RadiusStackCap = cfg.Bind("2. Skill Effect Radius", "RadiusStackCap", 300, "Stardust stacks up to this count grow skill effect radii at the full RadiusGrowthPerStack rate."); PostCapRadiusMultiplier = cfg.Bind("2. Skill Effect Radius", "PostCapRadiusMultiplier", 0.5f, "Falling Star and The Skies Descend: Stardust stacks ABOVE RadiusStackCap still grow the radius, but each contributes this fraction of RadiusGrowthPerStack. Singularity ignores this and is hard-capped (stacks above the cap add no radius)."); SingularityCooldown = cfg.Bind("3. Skill Cooldowns", "SingularityCooldown", 12f, "Singularity (alt secondary) base recharge, seconds. Default: 10."); FallingStarCooldown = cfg.Bind("3. Skill Cooldowns", "FallingStarCooldown", 24f, "Falling Star (alt special) base recharge, seconds. Default: 24. Stock game: 12."); SkiesDescendCooldown = cfg.Bind("3. Skill Cooldowns", "SkiesDescendCooldown", 24f, "The Skies Descend (Stardust special override at 900 stacks) base recharge, seconds. Default: 24. Stock game: 12."); FallingStarDamageCoefficient = cfg.Bind("4. Falling Star / The Skies Descend impact", "FallingStarDamageCoefficient", 10f, "Falling Star impact damage as a fraction of base damage. 10 = 1000%. Default: 10 (1000%). Stock game: 5 (500%)."); SkiesDescendDamageCoefficient = cfg.Bind("4. Falling Star / The Skies Descend impact", "SkiesDescendDamageCoefficient", 30f, "The Skies Descend star-impact damage as a fraction of base damage. 30 = 3000%. Default: 30."); FallingStarProcCoefficient = cfg.Bind("4. Falling Star / The Skies Descend impact", "FallingStarProcCoefficient", 1.5f, "Falling Star impact proc coefficient. Default: inherited from Captain Airstrike (~1.0)."); SkiesDescendProcCoefficient = cfg.Bind("4. Falling Star / The Skies Descend impact", "SkiesDescendProcCoefficient", 2f, "The Skies Descend star-impact proc coefficient. Default: inherited from Captain Airstrike (~1.0)."); ShockwaveRadiusMultiplier = cfg.Bind("5. The Skies Descend Shockwave", "ShockwaveRadiusMultiplier", 2f, "Overall size multiplier for the expanding ground shockwave (the second, larger AoE). 2.0 = +100%."); ShockwaveMaxGrowthPerStack = cfg.Bind("5. The Skies Descend Shockwave", "ShockwaveMaxGrowthPerStack", 0.06f, "Shockwave outer/maximum radius added per Stardust stack (before the game's internal x2.5). Default: 0.06."); ShockwaveDamageCoefficient = cfg.Bind("5. The Skies Descend Shockwave", "ShockwaveDamageCoefficient", 8f, "Shockwave per-hit damage as a fraction of base damage. 18 = 1800%. Default: 18. The shockwave proc coefficient stays 0."); RewriteDescriptions = cfg.Bind("6. Descriptions", "RewriteDescriptions", true, "Overwrite the in-game skill descriptions for Singularity / Falling Star / The Skies Descend / the Stardust passive so their numbers match this config and the True Cosmic Dragon add-on."); ImpactFlashWeight = cfg.Bind("7. Impact Visuals", "ImpactFlashWeight", 0.3f, "Weight (0..1) of the full-screen post-processing flash on the Falling Star / The Skies Descend star impact. 0 removes the white screen wash entirely; 1 is the stock intensity. Both skills share this effect."); ImpactLightMultiplier = cfg.Bind("7. Impact Visuals", "ImpactLightMultiplier", 0.3f, "Multiplier on the impact flash's point-light intensity. 1 is stock."); ShockwaveStardustDamageMultiplier = cfg.Bind("8. Other Stardust Scaling", "ShockwaveStardustDamageMultiplier", 0.025f, "Multiplier on the Skies Descend shockwave's flat per-Stardust-stack damage bonus (stock: 0.05 damage per stack). 0.025 = 1/40th. This is separate from ShockwaveDamageCoefficient, which is the base multiple of your damage stat."); BreathOfLightBurstStardustMultiplier = cfg.Bind("8. Other Stardust Scaling", "BreathOfLightBurstStardustMultiplier", 0.8f, "Multiplier on the Stardust scaling of Breath of Light's 150% burst (stock: the burst is damage * (attackSpeed * 1.5 + starCount * 0.01); this scales the 0.01 term). 0.8 = 80% of stock. 1 = stock. 0 = burst no longer scales with Stardust."); SolarFlareStardustAttackSpeedMultiplier = cfg.Bind("8. Other Stardust Scaling", "SolarFlareStardustAttackSpeedMultiplier", 0.5f, "Multiplier on Solar Flare's per-Stardust-stack fire-rate bonus (stock: starCount * 0.005 added to attack speed for that skill only). 0.5 = half. 1 = stock."); StarsurgeBaseDamageCoefficient = cfg.Bind("9. Starsurge & Comet of Legend", "StarsurgeBaseDamageCoefficient", 5f, "Starsurge star base damage as a fraction of your damage stat, before the blast-radius multiplier. Default: 5 (500%). Stock game: 4 (400%)."); StarsurgeGrowthPerSecond = cfg.Bind("9. Starsurge & Comet of Legend", "StarsurgeGrowthPerSecond", 3.5f, "How fast the Starsurge star's blast radius grows per second while NOT being carried by Comet of Legend. Default: 3.5. Stock game: 2.5."); StarsurgeCometGrowthMultiplier = cfg.Bind("9. Starsurge & Comet of Legend", "StarsurgeCometGrowthMultiplier", 0.5f, "Multiplier applied to the star's growth rate while Comet of Legend is carrying it (stock: the star grows at Aurelion's full move speed). 0.5 = half. 1 = stock."); StarsurgeStardustDamagePerStack = cfg.Bind("9. Starsurge & Comet of Legend", "StarsurgeStardustDamagePerStack", 0.005f, "Flat bonus added to the star's effective blast radius per Stardust stack in the detonation-damage formula. Stock game: 0.005."); StarsurgeBlastRadiusDamageMultiplier = cfg.Bind("9. Starsurge & Comet of Legend", "StarsurgeBlastRadiusDamageMultiplier", 0.65f, "Multiplier on the whole (blastRadius + stardust) / 10 damage multiplier at both Starsurge detonation sites. Default: 0.65. 0.5 = half - a star that has grown large hits half as hard. 1 = stock."); StarsurgeMaxDistance = cfg.Bind("9. Starsurge & Comet of Legend", "StarsurgeMaxDistance", 18f, "How far the Starsurge star may drift from Aurelion before it auto-detonates. Default: 18. Stock game: 13."); CometSpeedMultiplier = cfg.Bind("9. Starsurge & Comet of Legend", "CometSpeedMultiplier", 1.6f, "Comet of Legend movement-speed multiplier, applied on top of True Cosmic Dragon's [Flight] CometSpeedMultiplier. Default: 1.6 (60% faster)."); CometDamageReduction = cfg.Bind("9. Starsurge & Comet of Legend", "CometDamageReduction", 0.8f, "Fraction of incoming damage negated while dashing with Comet of Legend. Default: 0.8 (take 80% less). 0 = no reduction."); } } }