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 TowerShieldRebalance v1.0.0
TowerShieldRebalance.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; 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 HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("TowerShieldRebalance")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("TowerShieldRebalance")] [assembly: AssemblyTitle("TowerShieldRebalance")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.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 TowerShieldRebalance { internal sealed class ConfigurationManagerAttributes { public Action<ConfigEntryBase> CustomDrawer; } [BepInPlugin("org.bepinex.plugins.towershieldrebalance", "Tower Shield Rebalance", "1.0.0")] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public class TowerShieldRebalancePlugin : BaseUnityPlugin { private class OriginalData { public float BlockPower; public float BlockPowerPerLevel; public float MovementModifier; public List<DamageModPair> Modifiers; } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDBAwakePatch { private static void Postfix() { ApplyAll(); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class ObjectDBCopyPatch { private static void Postfix() { ApplyAll(); } } [HarmonyPatch(typeof(Humanoid))] [HarmonyPatch("BlockAttack")] private static class BlockPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); try { int num = list.FindLastIndex((CodeInstruction p) => p.opcode == OpCodes.Callvirt && p.operand != null && p.operand.ToString().Contains("Damage(HitData)")); if (num > 0) { MethodInfo methodInfo = AccessTools.Method(typeof(TowerShieldRebalancePlugin), "OnBlockHit", (Type[])null, (Type[])null); List<Label> labels = list[num].labels; list[num].labels = new List<Label>(); CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null); val.labels = labels; list.RemoveAt(num); list.Insert(num, val); list.Insert(num + 1, new CodeInstruction(OpCodes.Ldloc_0, (object)null)); list.Insert(num + 2, new CodeInstruction(OpCodes.Ldarg_1, (object)null)); list.Insert(num + 3, new CodeInstruction(OpCodes.Call, (object)methodInfo)); Debug.Log((object)"[TowerShieldRebalance] Patch successful!"); return list; } Debug.Log((object)("[TowerShieldRebalance] Patching failed. damageCallIndex: " + num)); } catch (Exception ex) { Debug.LogError((object)("[TowerShieldRebalance] " + ex.Message)); } return instructions; } } public const string PluginGuid = "org.bepinex.plugins.towershieldrebalance"; public const string PluginName = "Tower Shield Rebalance"; public const string PluginVersion = "1.0.0"; private const float GoldSpeedPenalty = 0.2f; private static readonly string[] TowerShields = new string[7] { "ShieldWoodTower", "ShieldBoneTower", "ShieldIronTower", "ShieldSerpentscale", "ShieldBlackmetalTower", "ShieldFlametalTower", "ShieldGoldTower" }; internal static ConfigEntry<float> BaseBlockScale; internal static ConfigEntry<float> UpgradeBlockScale; internal static ConfigEntry<bool> DisableKnockback; internal static ConfigEntry<bool> EnableThorns; internal static ConfigEntry<float> MaxThornsPercent; internal static ConfigEntry<float> MinThornsPercent; internal static ConfigEntry<float> SkillCurvePower; internal static ConfigEntry<bool> EnableShieldBonuses; private static readonly Dictionary<string, OriginalData> Originals = new Dictionary<string, OriginalData>(); private const DamageType Blunt = (DamageType)1; private const DamageType Slash = (DamageType)2; private const DamageType Pierce = (DamageType)4; private const DamageType Fire = (DamageType)32; private const DamageType Frost = (DamageType)64; private const DamageType Lightning = (DamageType)128; private const DamageType Poison = (DamageType)256; private const DamageModifier SlightRes = (DamageModifier)7; private const DamageModifier Res = (DamageModifier)1; private const DamageModifier VeryRes = (DamageModifier)5; private const DamageModifier SlightWeak = (DamageModifier)8; private const DamageModifier Weak = (DamageModifier)2; private static readonly Dictionary<string, DamageModPair[]> Bonuses = new Dictionary<string, DamageModPair[]> { ["ShieldWoodTower"] = (DamageModPair[])(object)new DamageModPair[3] { M((DamageType)32, (DamageModifier)8), M((DamageType)4, (DamageModifier)7), M((DamageType)1, (DamageModifier)7) }, ["ShieldBoneTower"] = (DamageModPair[])(object)new DamageModPair[3] { M((DamageType)1, (DamageModifier)8), M((DamageType)4, (DamageModifier)1), M((DamageType)2, (DamageModifier)7) }, ["ShieldIronTower"] = (DamageModPair[])(object)new DamageModPair[3] { M((DamageType)4, (DamageModifier)7), M((DamageType)2, (DamageModifier)7), M((DamageType)64, (DamageModifier)8) }, ["ShieldSerpentscale"] = (DamageModPair[])(object)new DamageModPair[3] { M((DamageType)2, (DamageModifier)7), M((DamageType)256, (DamageModifier)1), M((DamageType)64, (DamageModifier)2) }, ["ShieldBlackmetalTower"] = (DamageModPair[])(object)new DamageModPair[6] { M((DamageType)4, (DamageModifier)1), M((DamageType)2, (DamageModifier)7), M((DamageType)1, (DamageModifier)7), M((DamageType)256, (DamageModifier)8), M((DamageType)32, (DamageModifier)8), M((DamageType)128, (DamageModifier)8) }, ["ShieldFlametalTower"] = (DamageModPair[])(object)new DamageModPair[6] { M((DamageType)4, (DamageModifier)1), M((DamageType)2, (DamageModifier)7), M((DamageType)1, (DamageModifier)7), M((DamageType)32, (DamageModifier)7), M((DamageType)128, (DamageModifier)2), M((DamageType)64, (DamageModifier)2) }, ["ShieldGoldTower"] = (DamageModPair[])(object)new DamageModPair[7] { M((DamageType)4, (DamageModifier)5), M((DamageType)1, (DamageModifier)1), M((DamageType)2, (DamageModifier)1), M((DamageType)256, (DamageModifier)2), M((DamageType)64, (DamageModifier)2), M((DamageType)32, (DamageModifier)2), M((DamageType)128, (DamageModifier)2) } }; private readonly Harmony _harmony = new Harmony("org.bepinex.plugins.towershieldrebalance"); private static float R1(float v) { return Mathf.Round(v * 10f) / 10f; } private static Action<ConfigEntryBase> Drawer(float min, float max) { return delegate(ConfigEntryBase entry) { ConfigEntry<float> val = (ConfigEntry<float>)(object)entry; float num = R1(val.Value); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); float v = GUILayout.HorizontalSlider(num, min, max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); GUILayout.Label(num.ToString("F1", CultureInfo.InvariantCulture), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(48f) }); GUILayout.EndHorizontal(); v = Mathf.Clamp(R1(v), min, max); if (Mathf.Abs(v - val.Value) > 0.001f) { val.Value = v; } }; } private static ConfigEntry<float> BindFloat(ConfigFile cfg, string section, string key, float defaultValue, float min, float max, string description) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown return cfg.Bind<float>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), new object[1] { new ConfigurationManagerAttributes { CustomDrawer = Drawer(min, max) } })); } private static DamageModPair M(DamageType type, DamageModifier mod) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0013: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) return new DamageModPair { m_type = type, m_modifier = mod }; } private void Awake() { BaseBlockScale = BindFloat(((BaseUnityPlugin)this).Config, "1. Block", "BaseBlockScale", 20f, 0f, 100f, "BBS. Percentage increase of the base block armor of tower shields (20 = +20%). Formula: original block armor x (1 + BBS / 100)."); UpgradeBlockScale = BindFloat(((BaseUnityPlugin)this).Config, "1. Block", "UpgradeBlockScale", 4f, 0f, 20f, "UBS. Value added to the block armor gained per upgrade level of tower shields (original value + UBS)."); DisableKnockback = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Knockback", "DisableKnockback", false, "Disable enemy knockback when blocking (tower shields only)."); EnableThorns = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Thorns", "EnableThorns", true, "Deal return damage to the attacker when blocking with a tower shield."); MaxThornsPercent = BindFloat(((BaseUnityPlugin)this).Config, "3. Thorns", "MaxThornsPercent", 30f, 0f, 100f, "Maximum return damage, % of the shield's block armor (including the Blocking skill)."); MinThornsPercent = BindFloat(((BaseUnityPlugin)this).Config, "3. Thorns", "MinThornsPercent", 10f, 0f, 100f, "Minimum return damage, % of the shield's block armor (including the Blocking skill)."); SkillCurvePower = BindFloat(((BaseUnityPlugin)this).Config, "3. Thorns", "SkillCurvePower", 2f, 1f, 5f, "Blocking skill curve power. Higher values make return damage grow faster at low skill levels and slower close to level 100 (1 = linear)."); EnableShieldBonuses = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Shield bonuses", "EnableShieldBonuses", true, "Enable the changed resistances and weaknesses of tower shields (the Gold Tower Shield also gets a 20% movement speed penalty)."); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { ApplyAll(); }; _harmony.PatchAll(); } private void OnDestroy() { _harmony.UnpatchSelf(); } internal static void ApplyAll() { //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items == null || ObjectDB.instance.m_items.Count == 0) { return; } string[] towerShields = TowerShields; foreach (string text in towerShields) { try { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text); if ((Object)(object)itemPrefab == (Object)null) { continue; } ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { continue; } SharedData shared = component.m_itemData.m_shared; if (!Originals.TryGetValue(text, out var value)) { value = new OriginalData { BlockPower = shared.m_blockPower, BlockPowerPerLevel = shared.m_blockPowerPerLevel, MovementModifier = shared.m_movementModifier, Modifiers = ((shared.m_damageModifiers != null) ? new List<DamageModPair>(shared.m_damageModifiers) : new List<DamageModPair>()) }; Originals[text] = value; } shared.m_blockPower = value.BlockPower * (1f + R1(BaseBlockScale.Value) / 100f); shared.m_blockPowerPerLevel = value.BlockPowerPerLevel + R1(UpgradeBlockScale.Value); shared.m_movementModifier = value.MovementModifier; List<DamageModPair> list = new List<DamageModPair>(value.Modifiers); if (EnableShieldBonuses.Value && Bonuses.TryGetValue(text, out var value2)) { DamageModPair[] array = value2; for (int j = 0; j < array.Length; j++) { DamageModPair pair = array[j]; list.RemoveAll((DamageModPair m) => m.m_type == pair.m_type); list.Add(pair); } if (text == "ShieldGoldTower") { shared.m_movementModifier = value.MovementModifier - 0.2f; } } shared.m_damageModifiers = list; } catch (Exception ex) { Debug.LogError((object)("[TowerShieldRebalance] Error while processing " + text + ": " + ex)); } } } private static bool IsTowerShield(ItemData item) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return false; } return Array.IndexOf(TowerShields, ((Object)item.m_dropPrefab).name) >= 0; } public static void OnBlockHit(Character attacker, HitData pushHit, Humanoid blocker, ItemData currentBlocker, HitData originalHit) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)attacker == (Object)null || pushHit == null) { return; } if (IsTowerShield(currentBlocker)) { if (DisableKnockback.Value) { pushHit.m_pushForce = 0f; } if (EnableThorns.Value && (Object)(object)blocker != (Object)null) { float num = Mathf.Clamp01(((Character)blocker).GetSkillFactor((SkillType)6)); float blockPower = currentBlocker.GetBlockPower(num); float num2 = Mathf.Clamp01(R1(MaxThornsPercent.Value) / 100f); float num3 = Mathf.Min(Mathf.Clamp01(R1(MinThornsPercent.Value) / 100f), num2); float num4 = 1f - Mathf.Pow(1f - num, R1(SkillCurvePower.Value)); float num5 = Mathf.Clamp(num3 + (num2 - num3) * num4, num3, num2); float num6 = blockPower * num5; if (num6 > 0f) { pushHit.m_damage = default(DamageTypes); pushHit.m_damage.m_pierce = num6; if ((Object)(object)DamageText.instance != (Object)null && originalHit != null) { DamageText.instance.ShowText((TextType)0, originalHit.m_point + Vector3.up * 0.5f, num6, false); } } } } attacker.Damage(pushHit); } } }