Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TippingPoint v1.0.3
TippingPoint.dll
Decompiled 20 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("TippingPoint")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3+f66080e2ea7536265c743a5f2e1dd58018bb05ba")] [assembly: AssemblyProduct("TippingPoint")] [assembly: AssemblyTitle("TippingPoint")] [assembly: AssemblyVersion("1.0.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 TippingPoint { internal static class Backstab { private const float CooldownSeconds = 300f; private static readonly FieldRef<Character, float> BackstabTime = AccessTools.FieldRefAccess<Character, float>("m_backstabTime"); public static void TryOpenSide(Character victim, Character attacker, HitData hit) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)attacker == (Object)null) && attacker.IsPlayer() && !(hit.m_backstabBonus <= 1f)) { BaseAI component = ((Component)victim).GetComponent<BaseAI>(); if (!((Object)(object)component == (Object)null) && component.IsAlerted() && !(Vector3.Dot(hit.m_dir, ((Component)victim).transform.forward) <= 0f) && !(Time.time - BackstabTime.Invoke(victim) <= 300f)) { BackstabTime.Invoke(victim) = Time.time; hit.ApplyModifier(hit.m_backstabBonus); victim.m_backstabHitEffects.Create(hit.m_point, Quaternion.identity, ((Component)victim).transform, 1f, -1, attacker.GetZDOID()); } } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] internal static class CharacterDamagePatch { private static void Prefix(Character __instance, HitData hit) { if (Tiers.Ready && hit != null && __instance.IsOwner()) { Character attacker = hit.GetAttacker(); if (__instance.IsPlayer()) { ScaleCreatureDamage(attacker, hit); return; } Backstab.TryOpenSide(__instance, attacker, hit); SuppressStaggerBonus(__instance, hit); } } private static void SuppressStaggerBonus(Character victim, HitData hit) { if (victim.GetLevel() >= 3 && victim.IsStaggering()) { hit.ApplyModifier(0.5f); } } private static void ScaleCreatureDamage(Character attacker, HitData hit) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if ((Object)(object)attacker == (Object)null || attacker.IsPlayer() || attacker.m_boss || (int)attacker.GetFaction() == 8) { return; } int tier = Tiers.TierOf(attacker); float num = Baseline.For(attacker); if (!(num <= 0f)) { float num2 = Tiers.ScaleFor(num, tier); if (!Mathf.Approximately(num2, 1f)) { hit.ApplyModifier(num2); } } } } internal static class Baseline { private static readonly Dictionary<string, float> cache = new Dictionary<string, float>(); public static float For(Character character) { string text = Name(character); if (text == null) { return 0f; } if (cache.TryGetValue(text, out var value)) { return value; } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(text) : null); Humanoid val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Humanoid>() : null); if ((Object)(object)val2 == (Object)null) { return 0f; } float max = 0f; Consider(val2.m_defaultItems, ref max); Consider(val2.m_randomWeapon, ref max); if (val2.m_randomSets != null) { ItemSet[] randomSets = val2.m_randomSets; foreach (ItemSet val3 in randomSets) { if (val3 != null) { Consider(val3.m_items, ref max); } } } if (val2.m_randomItems != null) { RandomItem[] randomItems = val2.m_randomItems; foreach (RandomItem val4 in randomItems) { if (val4 != null) { ConsiderOne(val4.m_prefab, ref max); } } } if ((Object)(object)val2.m_unarmedWeapon != (Object)null) { ConsiderItem(val2.m_unarmedWeapon, ref max); } cache[text] = max; if (Tiers.LogScaling) { int num = Tiers.TierOf(character); Tiers.Log.LogInfo((object)($"{text}: tier {num}, own damage {max:0.#}, scaled to {Tiers.TargetDamage(num):0.#}" + ((max <= 0f) ? " - no weapon found, left at vanilla" : string.Empty))); } return max; } private static void Consider(GameObject[] items, ref float max) { if (items != null) { for (int i = 0; i < items.Length; i++) { ConsiderOne(items[i], ref max); } } } private static void ConsiderOne(GameObject item, ref float max) { ConsiderItem(((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null, ref max); } private static void ConsiderItem(ItemDrop drop, ref float max) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)drop == (Object)null) && drop.m_itemData?.m_shared != null) { float num = PlayerFacingDamage(drop.m_itemData.GetDamage()) * HardestAttack(drop.m_itemData.m_shared); if (num > max) { max = num; } } } private static float HardestAttack(SharedData shared) { float num = 1f; if (shared.m_attack != null) { num = Mathf.Max(num, shared.m_attack.m_damageMultiplier); } if (shared.m_secondaryAttack != null && !string.IsNullOrEmpty(shared.m_secondaryAttack.m_attackAnimation)) { num = Mathf.Max(num, shared.m_secondaryAttack.m_damageMultiplier); } return num; } private static float PlayerFacingDamage(DamageTypes damage) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) return damage.m_blunt + damage.m_slash + damage.m_pierce + damage.m_fire + damage.m_frost + damage.m_lightning + damage.m_poison + damage.m_spirit; } private static string Name(Character character) { if ((Object)(object)character == (Object)null) { return null; } string name = ((Object)((Component)character).gameObject).name; int num = name.IndexOf("(Clone)"); if (num <= 0) { return name; } return name.Substring(0, num); } } [HarmonyPatch(typeof(Attack), "GetLevelDamageFactor")] internal static class StarDamagePatch { private static readonly FieldRef<Attack, Humanoid> CharacterOf = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character"); private static void Postfix(Attack __instance, ref float __result) { if (Tiers.Ready && Tiers.RemoveStarDamage) { Humanoid val = CharacterOf.Invoke(__instance); if (!((Object)(object)val == (Object)null) && !((Character)val).IsPlayer()) { __result = 1f; } } } } [HarmonyPatch(typeof(BaseAI), "Awake")] internal static class BaseAiAwakePatch { private static void Postfix(BaseAI __instance) { if (Tiers.Ready) { Tiers.Stamp(((Component)__instance).GetComponent<Character>()); } } } [HarmonyPatch(typeof(Character), "AddStaggerDamage")] internal static class StaggerFloorPatch { private static void Prefix(Character __instance, ref float damage) { if (!Tiers.Ready || damage <= 0f || __instance.IsPlayer()) { return; } float num = Tiers.StaggerFloor(Tiers.TierOf(__instance)); if (!(num <= 0f)) { float num2 = __instance.GetMaxHealth() * __instance.m_staggerDamageFactor; if (!(num2 <= 0f) && !(num2 >= num)) { damage *= num2 / num; } } } } internal static class Stars { private const float SpeedPerStar = 0.03f; private const float SizePerStar = 0.02f; private const float AttackRatePerStar = 0.1f; private const float MaxAttackRate = 2f; private static int ExtraStars(int level) { return Mathf.Max(0, level - 2); } public static float SpeedMultiplier(int level) { return 1f + 0.03f * (float)Mathf.Max(0, level - 1); } public static float SizeMultiplier(int level) { return 1f + 0.02f * (float)Mathf.Max(0, level - 1); } public static float CooldownCut(int level) { float num = Mathf.Min(2f, 1f + 0.1f * (float)ExtraStars(level)); if (!(num <= 1f)) { return (num - 1f) / num; } return 0f; } } [HarmonyPatch(typeof(Character), "Awake")] internal static class StarSpeedPatch { private static void Postfix(Character __instance) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (!Tiers.Ready || !Tiers.RemoveStarDamage || __instance.IsPlayer()) { return; } int level = __instance.GetLevel(); if (level > 1) { float num = Stars.SpeedMultiplier(level); __instance.m_speed *= num; __instance.m_runSpeed *= num; __instance.m_turnSpeed *= num; if (!__instance.InInterior()) { Transform transform = ((Component)__instance).transform; transform.localScale *= Stars.SizeMultiplier(level); } } } } [HarmonyPatch(typeof(MonsterAI), "DoAttack")] internal static class StarAttackRatePatch { private static void Postfix(MonsterAI __instance, bool __result) { if (!__result || !Tiers.Ready || !Tiers.RemoveStarDamage) { return; } Character component = ((Component)__instance).GetComponent<Character>(); if ((Object)(object)component == (Object)null) { return; } float num = Stars.CooldownCut(component.GetLevel()); if (!(num <= 0f)) { Character obj = ((component is Humanoid) ? component : null); ItemData val = ((obj != null) ? ((Humanoid)obj).GetCurrentWeapon() : null); if (val?.m_shared != null) { val.m_lastAttackTime -= val.m_shared.m_aiAttackInterval * num; } } } } internal static class Tiers { private static readonly int TierKey = StringExtensionMethods.GetStableHashCode("tp_tier"); private static ConfigEntry<float> difficulty; private static ConfigEntry<float>[] anchors; private static ConfigEntry<int> oceanTier; private static ConfigEntry<int> unknownTier; private static ConfigEntry<bool> removeStarDamage; private static ConfigEntry<bool> logScaling; private static ManualLogSource log; public const bool OpenSideBackstab = true; private const float Compression = 0.6f; public static bool Ready => anchors != null; public static float Difficulty => difficulty.Value; public static bool RemoveStarDamage => removeStarDamage.Value; public static bool LogScaling => logScaling.Value; public static ManualLogSource Log => log; public static void Bind(ConfigEntry<float> difficultyEntry, ConfigEntry<float>[] anchorEntries, ConfigEntry<int> oceanTierEntry, ConfigEntry<int> unknownTierEntry, ConfigEntry<bool> removeStarDamageEntry, ConfigEntry<bool> logScalingEntry, ManualLogSource logger) { difficulty = difficultyEntry; anchors = anchorEntries; oceanTier = oceanTierEntry; unknownTier = unknownTierEntry; removeStarDamage = removeStarDamageEntry; logScaling = logScalingEntry; log = logger; } public static float Anchor(int tier) { if (tier < 1 || tier > 8) { return 0f; } return anchors[tier].Value; } public static float TargetDamage(int tier) { return Anchor(tier) * Difficulty; } public static float ScaleFor(float baseline, int tier) { float num = TargetDamage(tier); if (num <= 0f || baseline <= 0f) { return 1f; } float num2 = num / baseline; if (!(num2 <= 1f)) { return Mathf.Pow(num2, 0.6f); } return 1f; } public static float StaggerFloor(int tier) { if (tier < 2 || tier > 8) { return 0f; } return Anchor(tier - 1) * 2f; } public static int TierOf(Character character) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) ZDO val = ZdoOf(character); if (val == null) { return 0; } int num = val.GetInt(TierKey, 0); if (num != 0) { return num; } int num2 = TierAt(((Component)character).transform.position); if (num2 != 0 && character.IsOwner()) { val.Set(TierKey, num2, false); } return num2; } public static void Stamp(Character character) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || !character.IsOwner()) { return; } ZDO val = ZdoOf(character); if (val != null && val.GetInt(TierKey, 0) == 0) { int num = TierAt(((Component)character).transform.position); if (num != 0) { val.Set(TierKey, num, false); } } } private static ZDO ZdoOf(Character character) { if ((Object)(object)character == (Object)null) { return null; } ZNetView component = ((Component)character).GetComponent<ZNetView>(); if (!((Object)(object)component != (Object)null) || !component.IsValid()) { return null; } return component.GetZDO(); } private static int TierAt(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) Biome val = Heightmap.FindBiome(position); if ((int)val == 0 && WorldGenerator.instance != null) { val = WorldGenerator.instance.GetBiome(position); } return TierOf(val); } private static int TierOf(Biome biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 if ((int)biome <= 16) { switch (biome - 1) { default: if ((int)biome != 8) { if ((int)biome != 16) { break; } return 5; } return 2; case 0: return 1; case 1: return 3; case 3: return 4; case 2: break; } } else if ((int)biome <= 64) { if ((int)biome == 32) { return 7; } if ((int)biome == 64) { return 8; } } else { if ((int)biome == 256) { return oceanTier.Value; } if ((int)biome == 512) { return 6; } } return unknownTier.Value; } } [BepInPlugin("elric.TippingPoint", "Tipping Point", "1.0.3")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class TippingPoint : BaseUnityPlugin { public const string PluginGUID = "elric.TippingPoint"; public const string PluginName = "Tipping Point"; public const string PluginVersion = "1.0.3"; private void Awake() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) CreateConfig(); new Harmony("elric.TippingPoint").PatchAll(); } private void CreateConfig() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown ConfigEntry<float> difficultyEntry = ((BaseUnityPlugin)this).Config.Bind<float>("Difficulty", "Difficulty", 1.9f, new ConfigDescription("How hard creatures hit. Higher means every creature is pulled further toward what its biome expects of your armour - though never all the way, so the weak stay weaker than the strong. 1.5 is forgiving, 1.9 normal, 2.1 demanding. Going high is safe here: creatures are moved proportionally, so a large value lifts the whole biome rather than pushing its hardest hitters past the point where your shield still works.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), new object[1] { Primary() })); ConfigEntry<bool> removeStarDamageEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Difficulty", "RemoveStarDamage", true, new ConfigDescription("Stars no longer add damage. Vanilla gives +50% per star, which is what turns a starred creature into a one-shot once its hit passes twice your armour. Off restores vanilla star damage.", (AcceptableValueBase)null, new object[1] { adminOnly() })); ConfigEntry<float>[] array = new ConfigEntry<float>[9]; string[] array2 = new string[9] { null, "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands", "DeepNorth" }; float[] array3 = new float[9] { 0f, 18f, 36f, 54f, 72f, 90f, 108f, 142f, 160f }; for (int i = 1; i <= 8; i++) { array[i] = ((BaseUnityPlugin)this).Config.Bind<float>("Anchors", array2[i], array3[i], new ConfigDescription("Armour a prepared player is expected to have in " + array2[i] + ". Raise it to make that biome harder, lower it to make it easier. Change this to fix one biome, not to change overall difficulty.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 1000f), new object[1] { Advanced() })); } ConfigEntry<int> oceanTierEntry = ((BaseUnityPlugin)this).Config.Bind<int>("Anchors", "OceanTier", 3, new ConfigDescription("Which biome's anchor to use for creatures that spawned in open water, since the ocean has no gear of its own.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), new object[1] { Advanced() })); ConfigEntry<int> unknownTierEntry = ((BaseUnityPlugin)this).Config.Bind<int>("Anchors", "UnknownTier", 0, new ConfigDescription("Which anchor to use when a creature's biome cannot be determined, which mainly means spawns inside dungeons. 0 leaves those creatures at their vanilla damage.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 8), new object[1] { Advanced() })); ConfigEntry<bool> logScalingEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogScaling", false, new ConfigDescription("Write one line to the log the first time each creature type is scaled, saying its biome, its own damage and what it was scaled to.", (AcceptableValueBase)null, Array.Empty<object>())); Tiers.Bind(difficultyEntry, array, oceanTierEntry, unknownTierEntry, removeStarDamageEntry, logScalingEntry, ((BaseUnityPlugin)this).Logger); static ConfigurationManagerAttributes Advanced() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = true }; } static ConfigurationManagerAttributes Primary() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown return new ConfigurationManagerAttributes { IsAdminOnly = true, Order = 100 }; } static ConfigurationManagerAttributes adminOnly() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown return new ConfigurationManagerAttributes { IsAdminOnly = true }; } } } }