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 VikingLib v0.2.2
VikingLib.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; using VikingLib.Combat; using VikingLib.Combat.Attacks; using VikingLib.Combat.Defense; using VikingLib.Combat.Roll; using VikingLib.Combat.Stagger; using VikingLib.Combat.Telemetry; using VikingLib.Configuration; using VikingLib.Patches; using VikingLib.SkillSystem; using VikingLib.Stats; using VikingLib.StatusEffects; using VikingLib.UI.Tooltip; [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("DigitalVikings")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Modular combat mechanics, canonical status effects, and damage calculation framework for Valheim.")] [assembly: AssemblyFileVersion("0.2.2.0")] [assembly: AssemblyInformationalVersion("0.2.2+897827c685052c7dd2c93aef59734e74b28a9683")] [assembly: AssemblyProduct("VikingLib")] [assembly: AssemblyTitle("VikingLib")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 VikingLib { [BepInPlugin("com.digitalvikings.vikinglib", "VikingLib", "0.2.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class VikingLibPlugin : BaseUnityPlugin { public const string ModGuid = "com.digitalvikings.vikinglib"; public const string ModName = "VikingLib"; public const string ModVersion = "0.2.2"; private Harmony _harmony; public static VikingLibPlugin Instance { get; private set; } public static ManualLogSource Log { get; internal set; } private void Awake() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"VikingLib v0.2.2 initializing..."); ModConfig.Init(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.digitalvikings.vikinglib"); _harmony.PatchAll(); CanonicalStatusEffects.Init(); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new TraceConsoleCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new LogConsoleCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ArmorConsoleCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new DumpAttacksConsoleCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new BuffTestConsoleCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new StatusEffectConsoleCommand()); HookJotunnSync(); Log.LogInfo((object)"VikingLib v0.2.2 loaded successfully. Combat pipeline and telemetry active."); } [MethodImpl(MethodImplOptions.NoInlining)] private void HookJotunnSync() { SynchronizationManager.OnConfigurationSynchronized += delegate { Log.LogInfo((object)"Server configuration synchronized successfully."); }; } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace VikingLib.UI { [HarmonyPatch] public static class CharacterStatsGlossaryPanel { public delegate IEnumerable<(string Label, string FormattedValue)>? CustomGlossaryCategoryProvider(Player player); private sealed class PrioritizedCategoryProvider { public string CategoryTitle { get; } public int Priority { get; } public CustomGlossaryCategoryProvider Provider { get; } public PrioritizedCategoryProvider(string categoryTitle, int priority, CustomGlossaryCategoryProvider provider) { CategoryTitle = categoryTitle; Priority = priority; Provider = provider; } } public const string TopicName = "Character Stats"; private static float _lastRefreshTime; private const float RefreshInterval = 0.5f; private static readonly List<PrioritizedCategoryProvider> _customCategories = new List<PrioritizedCategoryProvider>(); public static event Action<Player, StringBuilder>? OnFormatCustomSections; public static void RegisterCustomCategory(string categoryTitle, CustomGlossaryCategoryProvider provider, int priority = 100) { if (!string.IsNullOrEmpty(categoryTitle) && provider != null) { _customCategories.Add(new PrioritizedCategoryProvider(categoryTitle, priority, provider)); _customCategories.Sort((PrioritizedCategoryProvider a, PrioritizedCategoryProvider b) => a.Priority.CompareTo(b.Priority)); } } public static void RegisterCustomCategory(string categoryTitle, Func<Player, IEnumerable<string>?> lineProvider, int priority = 100) { if (string.IsNullOrEmpty(categoryTitle) || lineProvider == null) { return; } RegisterCustomCategory(categoryTitle, delegate(Player player) { IEnumerable<string> enumerable = lineProvider(player); if (enumerable == null) { return (IEnumerable<(string Label, string FormattedValue)>?)null; } List<(string, string)> list = new List<(string, string)>(); foreach (string item in enumerable) { list.Add((item, string.Empty)); } return list; }, priority); } [HarmonyPatch(typeof(TextsDialog), "UpdateTextsList")] [HarmonyPostfix] public static void PostfixUpdateTextsList(TextsDialog __instance) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (ModConfig.ModEnabled.Value && ModConfig.ShowStatsInGlossary.Value) { string text = FormatCharacterStats(Player.m_localPlayer); TextInfo item = new TextInfo("Character Stats", text); CharacterStatsHelper.GetTexts(__instance)?.Add(item); } } [HarmonyPatch(typeof(TextsDialog), "ShowText", new Type[] { typeof(TextInfo) })] [HarmonyPrefix] public static void PrefixShowText(TextsDialog __instance, TextInfo text) { if (ModConfig.ModEnabled.Value && ModConfig.ShowStatsInGlossary.Value && text != null && !(text.m_topic != "Character Stats")) { string text2 = FormatCharacterStats(Player.m_localPlayer); text.m_text = text2; _lastRefreshTime = Time.unscaledTime; } } [HarmonyPatch(typeof(TextsDialog), "Update")] [HarmonyPostfix] public static void PostfixUpdate(TextsDialog __instance) { if (!ModConfig.ModEnabled.Value || !ModConfig.ShowStatsInGlossary.Value || !((Component)__instance).gameObject.activeInHierarchy) { return; } float num = ModConfig.GlossaryRefreshInterval.Value; if (num <= 0.1f) { num = 1.5f; } if (Time.unscaledTime - _lastRefreshTime < num) { return; } List<TextInfo> texts = CharacterStatsHelper.GetTexts(__instance); if (texts == null) { return; } TextInfo val = null; for (int i = 0; i < texts.Count; i++) { TextInfo val2 = texts[i]; if (val2 != null && val2.m_topic == "Character Stats") { if ((Object)(object)val2.m_selected != (Object)null && val2.m_selected.activeSelf) { val = val2; break; } if ((Object)(object)__instance.m_textAreaTopic != (Object)null && __instance.m_textAreaTopic.text == "Character Stats") { val = val2; break; } } } if (val == null) { return; } _lastRefreshTime = Time.unscaledTime; string text = FormatCharacterStats(Player.m_localPlayer); if (!(val.m_text != text)) { return; } val.m_text = text; if ((Object)(object)__instance.m_textArea != (Object)null) { float value = (((Object)(object)__instance.m_rightScrollbar != (Object)null) ? __instance.m_rightScrollbar.value : 1f); __instance.m_textArea.text = text; if ((Object)(object)__instance.m_rightScrollbar != (Object)null) { __instance.m_rightScrollbar.value = value; } } } public static string FormatCharacterStats(Player? player) { //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return "No character currently active."; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("<size=125%><color=#FFCC00><b>CHARACTER OVERVIEW</b></color></size>\n"); stringBuilder.AppendLine("<color=orange><b>[ MAXIMUM ATTRIBUTES ]</b></color>"); AppendStatLine(stringBuilder, player, CharacterStatType.MaxHealth, "Max Health", "HP"); AppendStatLine(stringBuilder, player, CharacterStatType.MaxStamina, "Max Stamina", "pts"); AppendStatLine(stringBuilder, player, CharacterStatType.MaxEitr, "Max Eitr", "pts"); AppendStatLine(stringBuilder, player, CharacterStatType.MaxCarryWeight, "Max Carry Weight", "kg"); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.FoodHealthEffectiveness, "Food Health Effectiveness", "+%", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.FoodHealthRegenEffectiveness, "Food HP Regen Effectiveness", "+%", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.FoodStaminaEffectiveness, "Food Stamina Effectiveness", "+%", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.FoodEitrEffectiveness, "Food Eitr Effectiveness", "+%", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.FoodDurationMultiplier, "Food Duration", "x", 1f); stringBuilder.AppendLine(); stringBuilder.AppendLine("<color=orange><b>[ REGENERATION & RECOVERY ]</b></color>"); AppendStatLine(stringBuilder, player, CharacterStatType.HealthRegen, "Health Regeneration", "HP/s"); AppendStatLine(stringBuilder, player, CharacterStatType.HealthRegenDelay, "Combat Health Regen Delay", "sec"); float remainingRegenDelay = PlayerStatsPatch.GetRemainingRegenDelay((Character)(object)player); if (remainingRegenDelay > 0.05f) { stringBuilder.AppendLine($" <color=#FF9933>└─ Status: Paused in combat ({remainingRegenDelay:F1}s remaining)</color>"); } AppendStatLine(stringBuilder, player, CharacterStatType.StaminaRegen, "Stamina Regeneration", "pts/s"); AppendStatLine(stringBuilder, player, CharacterStatType.EitrRegen, "Eitr Regeneration", "pts/s"); AppendStatLine(stringBuilder, player, CharacterStatType.StaminaRegenDelay, "Stamina Recovery Delay", "sec"); stringBuilder.AppendLine(); stringBuilder.AppendLine("<color=orange><b>[ DEFENSE & RESISTANCES ]</b></color>"); AppendStatLine(stringBuilder, player, CharacterStatType.BodyArmor, "Body Armor", "pts"); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.ArmorEfficiency, "Armor Efficiency", "+%", 0f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.BluntArmorEfficiency, "Blunt Armor Efficiency", "+%", 0f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.SlashArmorEfficiency, "Slash Armor Efficiency", "+%", 0f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.PierceArmorEfficiency, "Pierce Armor Efficiency", "+%", 0f); EntityDefenseData defense = EntityDefenseRegistry.GetDefense((Character)(object)player); List<(string, float, string, List<string>)> list = new List<(string, float, string, List<string>)>(); DamageType[] array = new DamageType[7] { DamageType.Blunt, DamageType.Slash, DamageType.Pierce, DamageType.Fire, DamageType.Frost, DamageType.Lightning, DamageType.Poison }; for (int i = 0; i < array.Length; i++) { DamageType type = array[i]; float resistanceForType = defense.GetResistanceForType(type); float num = 1f; CharacterStatType? resistanceStat = CharacterStatManager.GetResistanceStat(type); if (resistanceStat.HasValue) { num *= CharacterStatManager.GetStat((Character?)(object)player, resistanceStat.Value); } if (type.IsPhysical()) { num *= CharacterStatManager.GetStat((Character?)(object)player, CharacterStatType.ResistancePhysical); } else if (type.IsElemental()) { num *= CharacterStatManager.GetStat((Character?)(object)player, CharacterStatType.ResistanceElemental); } float num2 = resistanceForType * num; if (!(Mathf.Abs(num2 - 1f) > 0.001f)) { continue; } List<string> resistanceSources = GetResistanceSources(player, type); if (resistanceStat.HasValue) { foreach (var multiplier in CharacterStatManager.GetTrace((Character?)(object)player, resistanceStat.Value).Multipliers) { resistanceSources.Add($"{multiplier.Source} (x{multiplier.Value:F2})"); } } string item = ((object)EntityDefenseRegistry.ToVanillaModifier(num2)/*cast due to .constrained prefix*/).ToString(); list.Add((type.ToString(), num2, item, resistanceSources)); } if (list.Count > 0) { stringBuilder.AppendLine("• <b>Damage Resistances</b>:"); for (int j = 0; j < list.Count; j++) { (string, float, string, List<string>) tuple = list[j]; stringBuilder.AppendLine($" <color=yellow>{tuple.Item1} Taken</color>: {tuple.Item2:F2}x ({tuple.Item3})"); for (int k = 0; k < tuple.Item4.Count; k++) { string text = ((k == tuple.Item4.Count - 1) ? " <color=#A0A0A0>└─ " : " <color=#A0A0A0>├─ "); stringBuilder.AppendLine(text + "[Tier 3 Multiplier] " + tuple.Item4[k] + "</color>"); } } } AppendStatLineIfModified(stringBuilder, player, CharacterStatType.BlockPowerMultiplier, "Block Power Multiplier", "x", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.ParryMultiplier, "Parry Bonus Multiplier", "x", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.ParryWindow, "Parry Timing Window", "sec", 0.25f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.StaggerResistance, "Stagger Resistance", "x", 1f); stringBuilder.AppendLine(); StringBuilder stringBuilder2 = new StringBuilder(); StringBuilder stringBuilder3 = new StringBuilder(); AppendStatLineIfModified(stringBuilder3, player, CharacterStatType.DamageMelee, "Melee Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder3, player, CharacterStatType.DamageOneHanded, "One-Handed Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder3, player, CharacterStatType.DamageTwoHanded, "Two-Handed Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder3, player, CharacterStatType.DamageRanged, "Ranged Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder3, player, CharacterStatType.DamageMagic, "Magic Damage Bonus", "x", 1f, " "); if (stringBuilder3.Length > 0) { stringBuilder2.AppendLine(" <color=#FFE082><b>[ Delivery & Stance ]</b></color>"); stringBuilder2.Append(stringBuilder3.ToString()); } StringBuilder stringBuilder4 = new StringBuilder(); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.AttackSpeed, "Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.CriticalStrikeChance, "Critical Strike Chance", "%", ModConfig.DefaultPlayerCritChance.Value, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.CriticalStrikeMultiplier, "Critical Strike Multiplier", "x", ModConfig.DefaultCritMultiplier.Value, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.DamageSecondaryAttack, "Secondary Attack Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.DamageComboFinisher, "Combo Finisher Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.DamageSneak, "Sneak Attack Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.CleaveEfficiency, "Cleave Efficiency", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.StaggerDamage, "Stagger Power", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.KnockbackDealt, "Knockback Force", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.MeleeReach, "Melee Reach", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.BowDrawSpeed, "Bow Draw Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.CrossbowReloadSpeed, "Crossbow Reload Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder4, player, CharacterStatType.ProjectilePrecision, "Projectile Precision Rating", "x", 1f, " "); if (stringBuilder4.Length > 0) { stringBuilder2.AppendLine(" <color=#FFE082><b>[ Attack Styles & Techniques ]</b></color>"); stringBuilder2.Append(stringBuilder4.ToString()); } StringBuilder stringBuilder5 = new StringBuilder(); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.HealthOnKill, "Health On Kill", "HP", 0f, " "); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.StaminaOnKill, "Stamina On Kill", "pts", 0f, " "); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.EitrOnKill, "Eitr On Kill", "pts", 0f, " "); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.HealthOnDamageTaken, "Health On Damage Taken", "HP", 0f, " "); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.StaminaOnDamageTaken, "Stamina On Damage Taken", "pts", 0f, " "); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.EitrOnDamageTaken, "Eitr On Damage Taken", "pts", 0f, " "); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.HealthOnCauseStagger, "Health On Cause Stagger", "HP", 0f, " "); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.StaminaOnCauseStagger, "Stamina On Cause Stagger", "pts", 0f, " "); AppendStatLineIfModified(stringBuilder5, player, CharacterStatType.EitrOnCauseStagger, "Eitr On Cause Stagger", "pts", 0f, " "); if (stringBuilder5.Length > 0) { stringBuilder2.AppendLine(" <color=#FFE082><b>[ Combat Resource Recovery ]</b></color>"); stringBuilder2.Append(stringBuilder5.ToString()); } StringBuilder stringBuilder6 = new StringBuilder(); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageAgainstBosses, "Boss Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageAgainstStaggered, "Stagger Punish Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageAgainstAirborne, "Airborne Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageExecute, "Execute Damage (Target HP <= 35%)", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageFirstStrike, "First Strike (Target HP >= 90%)", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageBerserk, "Berserk Damage (Self HP <= 35%)", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageFlawless, "Flawless Damage (Self HP >= 90%)", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageAtNight, "Night Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageWhileAirborne, "Self-Airborne Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder6, player, CharacterStatType.DamageAgainstAfflicted, "Afflicted Target Damage", "x", 1f, " "); if (stringBuilder6.Length > 0) { stringBuilder2.AppendLine(" <color=#FFE082><b>[ Situational & Target Contexts ]</b></color>"); stringBuilder2.Append(stringBuilder6.ToString()); } StringBuilder stringBuilder7 = new StringBuilder(); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageSwords, "Swords Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedSwords, "Swords Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageKnives, "Knives Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedKnives, "Knives Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageClubs, "Clubs Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedClubs, "Clubs Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamagePolearms, "Polearms Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedPolearms, "Polearms Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageSpears, "Spears Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedSpears, "Spears Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageAxes, "Axes Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedAxes, "Axes Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageBows, "Bows Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedBows, "Bows Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageCrossbows, "Crossbows Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedCrossbows, "Crossbows Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageUnarmed, "Unarmed & Fist Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedUnarmed, "Unarmed Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageElementalMagic, "Elemental Magic Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedElementalMagic, "Elemental Magic Attack Speed", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.DamageBloodMagic, "Blood Magic Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder7, player, CharacterStatType.AttackSpeedBloodMagic, "Blood Magic Attack Speed", "x", 1f, " "); if (stringBuilder7.Length > 0) { stringBuilder2.AppendLine(" <color=#FFE082><b>[ Weapon Families ]</b></color>"); stringBuilder2.Append(stringBuilder7.ToString()); } StringBuilder stringBuilder8 = new StringBuilder(); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamagePhysical, "Physical Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamageSlashing, "Slashing Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamageBlunt, "Blunt Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamagePiercing, "Piercing Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamageElemental, "Elemental Damage Bonus", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamageFire, "Fire Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamageFrost, "Frost Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamageLightning, "Lightning Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamagePoison, "Poison Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamageSpirit, "Spirit Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamageChop, "Chop Damage", "x", 1f, " "); AppendStatLineIfModified(stringBuilder8, player, CharacterStatType.DamagePickaxe, "Pickaxe Damage", "x", 1f, " "); if (stringBuilder8.Length > 0) { stringBuilder2.AppendLine(" <color=#FFE082><b>[ Damage Types & Archetypes ]</b></color>"); stringBuilder2.Append(stringBuilder8.ToString()); } if (stringBuilder2.Length > 0) { stringBuilder.AppendLine("<color=orange><b>[ OFFENSIVE PROFICIENCIES ]</b></color>"); stringBuilder.Append(stringBuilder2.ToString()); stringBuilder.AppendLine(); } StringBuilder stringBuilder9 = new StringBuilder(); StringBuilder stringBuilder10 = new StringBuilder(); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.AttackStaminaEfficiency, "Attack Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.MeleeStaminaEfficiency, "Melee Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.OneHandedStaminaEfficiency, "One-Handed Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.TwoHandedStaminaEfficiency, "Two-Handed Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.RangedStaminaEfficiency, "Ranged Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.SecondaryAttackStaminaEfficiency, "Secondary Attack Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.AttackEitrEfficiency, "Attack Eitr Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.AttackHealthEfficiency, "Attack Health Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.SwordsEfficiency, "Swords Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.KnivesEfficiency, "Knives Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.ClubsEfficiency, "Clubs Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.PolearmsEfficiency, "Polearms Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.SpearsEfficiency, "Spears Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.AxesEfficiency, "Axes Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.BowsEfficiency, "Bows Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.CrossbowReloadStaminaEfficiency, "Crossbow Reload Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.UnarmedEfficiency, "Unarmed Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.ElementalMagicEitrEfficiency, "Elemental Magic Eitr Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.BloodMagicHealthEfficiency, "Blood Magic Health Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder10, player, CharacterStatType.BloodMagicEitrEfficiency, "Blood Magic Eitr Efficiency", "+%", 0f, " "); if (stringBuilder10.Length > 0) { stringBuilder9.AppendLine(" <color=#FFE082><b>[ Combat & Attack Resource Costs ]</b></color>"); stringBuilder9.Append(stringBuilder10.ToString()); } StringBuilder stringBuilder11 = new StringBuilder(); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.SprintEfficiency, "Sprint Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.JumpEfficiency, "Jump Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.DodgeEfficiency, "Dodge Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.SneakEfficiency, "Sneak Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.SwimEfficiency, "Swim Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.BowDrawStaminaEfficiency, "Bow Hold Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.BowDrawEitrEfficiency, "Staff Hold Eitr Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.FishingStaminaEfficiency, "Fishing Reel Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.BlockStaminaEfficiency, "Block Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.RidingStaminaEfficiency, "Riding Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.ToolStaminaEfficiency, "Tool Stamina Efficiency", "+%", 0f, " "); AppendStatLineIfModified(stringBuilder11, player, CharacterStatType.DurabilityEfficiency, "Durability Efficiency", "+%", 0f, " "); if (stringBuilder11.Length > 0) { stringBuilder9.AppendLine(" <color=#FFE082><b>[ Locomotion & World Activities ]</b></color>"); stringBuilder9.Append(stringBuilder11.ToString()); } if (stringBuilder9.Length > 0) { stringBuilder.AppendLine("<color=orange><b>[ ACTION RESOURCE EFFICIENCIES ]</b></color>"); stringBuilder.Append(stringBuilder9.ToString()); stringBuilder.AppendLine(); } stringBuilder.AppendLine("<color=orange><b>[ LOCOMOTION & SPEEDS ]</b></color>"); AppendVelocityStatLine(stringBuilder, player, CharacterStatType.JogSpeed, "Jog Speed", ((Character)player).m_speed); AppendVelocityStatLine(stringBuilder, player, CharacterStatType.RunSpeed, "Sprint Speed", ((Character)player).m_runSpeed); AppendStatLine(stringBuilder, player, CharacterStatType.WalkSpeed, "Walk Speed", "m/s"); AppendStatLine(stringBuilder, player, CharacterStatType.CrouchSpeed, "Crouch Speed", "m/s"); AppendStatLine(stringBuilder, player, CharacterStatType.SwimSpeed, "Swim Speed", "m/s"); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.JumpHeight, "Jump Apex Height", "m", 1.7f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.Concealment, "Stealth Concealment Rating", "x", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.RidingSpeed, "Mount Run Speed Factor", "x", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.RidingControl, "Mount Steering Obedience", "%", 0f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.ShipSailSpeed, "Ship Sail Speed (Wind)", "x", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.ShipRudderSpeed, "Ship Rudder Speed (Paddle)", "x", 1f); AppendStatLineIfModified(stringBuilder, player, CharacterStatType.CartWeightEfficiency, "Cart Weight Efficiency", "+%", 0f); stringBuilder.AppendLine(); StringBuilder stringBuilder12 = new StringBuilder(); AppendStatLineIfModified(stringBuilder12, player, CharacterStatType.HarvestRadius, "Harvest & Agriculture Radius", "x", 1f); AppendStatLineIfModified(stringBuilder12, player, CharacterStatType.CraftingYield, "Crafting Total Yield", "%", 1f); AppendStatLineIfModified(stringBuilder12, player, CharacterStatType.CookingYield, "Cooking Total Yield", "%", 1f); AppendStatLineIfModified(stringBuilder12, player, CharacterStatType.ForagingYield, "Foraging Total Yield", "%", 1f); AppendStatLineIfModified(stringBuilder12, player, CharacterStatType.MiningYield, "Mining Mineral Yield", "%", 1f); AppendStatLineIfModified(stringBuilder12, player, CharacterStatType.WoodcuttingYield, "Woodcutting Timber Yield", "%", 1f); AppendStatLineIfModified(stringBuilder12, player, CharacterStatType.MonsterDropYield, "Monster Slay Loot Yield", "%", 1f); if (stringBuilder12.Length > 0) { stringBuilder.AppendLine("<color=orange><b>[ GATHERING, CRAFTING & YIELDS ]</b></color>"); stringBuilder.Append(stringBuilder12.ToString()); stringBuilder.AppendLine(); } IReadOnlyCollection<CustomStatToken> all = StatRegistry.GetAll(); if (all.Count > 0) { StringBuilder stringBuilder13 = new StringBuilder(); foreach (CustomStatToken item2 in all) { StatTrace trace = CharacterStatManager.GetTrace((Character?)(object)player, item2.Key, item2.DefaultValue); if (trace.FlatModifiers.Count > 0 || trace.IncreasedModifiers.Count > 0 || trace.Multipliers.Count > 0 || Mathf.Abs(trace.FinalValue - item2.DefaultValue) > 0.001f) { AppendStatLineWithTrace(stringBuilder13, trace, item2.Name, item2.Unit); } } if (stringBuilder13.Length > 0) { stringBuilder.AppendLine("<color=orange><b>[ CUSTOM & MODDED STATS ]</b></color>"); stringBuilder.Append(stringBuilder13.ToString()); stringBuilder.AppendLine(); } } if (_customCategories.Count > 0) { for (int l = 0; l < _customCategories.Count; l++) { PrioritizedCategoryProvider prioritizedCategoryProvider = _customCategories[l]; try { IEnumerable<(string, string)> enumerable = prioritizedCategoryProvider.Provider(player); if (enumerable == null) { continue; } StringBuilder stringBuilder14 = new StringBuilder(); foreach (var (text2, text3) in enumerable) { if (!string.IsNullOrWhiteSpace(text2)) { if (string.IsNullOrEmpty(text3)) { stringBuilder14.AppendLine(" " + text2); continue; } stringBuilder14.AppendLine(" " + text2 + ": <color=orange>" + text3 + "</color>"); } } if (stringBuilder14.Length > 0) { stringBuilder.AppendLine("<color=orange><b>[ " + prioritizedCategoryProvider.CategoryTitle.ToUpperInvariant() + " ]</b></color>"); stringBuilder.Append(stringBuilder14.ToString()); stringBuilder.AppendLine(); } } catch (Exception ex) { ManualLogSource log = VikingLibPlugin.Log; if (log != null) { log.LogWarning((object)("Error rendering custom glossary category '" + prioritizedCategoryProvider.CategoryTitle + "': " + ex.Message)); } } } } try { CharacterStatsGlossaryPanel.OnFormatCustomSections?.Invoke(player, stringBuilder); } catch (Exception arg) { ManualLogSource log2 = VikingLibPlugin.Log; if (log2 != null) { log2.LogError((object)$"Error in glossary custom sections hook: {arg}"); } } return stringBuilder.ToString(); } private static void AppendVelocityStatLine(StringBuilder sb, Player player, CharacterStatType statType, string label, float baseVelocity) { StatTrace trace = CharacterStatManager.GetTrace((Character?)(object)player, statType); float num = baseVelocity * trace.FinalValue; if (trace.FlatModifiers.Count <= 0 && trace.IncreasedModifiers.Count <= 0 && trace.Multipliers.Count <= 0) { sb.AppendLine($"• <b>{label}</b>: <color=yellow>{num:F1} m/s</color>"); return; } sb.AppendLine($"• <b>{label}</b>: <color=yellow>{num:F1} m/s</color> <i>(Base: {baseVelocity:F1} m/s)</i>"); List<string> list = new List<string>(); foreach (var flatModifier in trace.FlatModifiers) { string item = flatModifier.Source; float item2 = flatModifier.Value; string arg = ((item2 >= 0f) ? "+" : ""); list.Add($"[Tier 1 Flat] {item}: {arg}{item2:F1}"); } foreach (var increasedModifier in trace.IncreasedModifiers) { string item3 = increasedModifier.Source; float item4 = increasedModifier.Value; string arg2 = ((item4 >= 0f) ? "+" : ""); list.Add($"[Tier 2 Additive] {item3}: {arg2}{item4 * 100f:F1}%"); } foreach (var (arg3, num2) in trace.Multipliers) { list.Add($"[Tier 3 Multiplier] {arg3}: x{num2:F2}"); } for (int i = 0; i < list.Count; i++) { string text = ((i == list.Count - 1) ? " <color=#A0A0A0>└─ " : " <color=#A0A0A0>├─ "); sb.AppendLine(text + list[i] + "</color>"); } } private static void AppendStatLine(StringBuilder sb, Player player, CharacterStatType statType, string label, string unit) { StatTrace trace = CharacterStatManager.GetTrace((Character?)(object)player, statType); AppendStatLineWithTrace(sb, trace, label, unit); } private static void AppendStatLineIfModified(StringBuilder sb, Player player, CharacterStatType statType, string label, string unit, float baseline, string indent = "") { StatTrace trace = CharacterStatManager.GetTrace((Character?)(object)player, statType); if (trace.FlatModifiers.Count > 0 || trace.IncreasedModifiers.Count > 0 || trace.Multipliers.Count > 0 || !(Mathf.Abs(trace.FinalValue - baseline) < 0.001f)) { AppendStatLineWithTrace(sb, trace, label, unit, indent); } } private static void AppendStatLineWithTrace(StringBuilder sb, StatTrace trace, string label, string unit, string indent = "") { float finalValue = trace.FinalValue; bool flag = IsEfficiencyStat(trace.StatType); string text = unit switch { "x" => $"{finalValue:F2}x", "%" => $"{finalValue * 100f:F0}%", "+%" => $"{(flag ? finalValue : (finalValue - 1f)) * 100f:+0.0;-0.0;0}%", "m" => $"{finalValue:F2}m", _ => string.IsNullOrEmpty(unit) ? $"{finalValue:F1}" : $"{finalValue:F1} {unit}", }; if (trace.FlatModifiers.Count <= 0 && trace.IncreasedModifiers.Count <= 0 && trace.Multipliers.Count <= 0) { sb.AppendLine(indent + "• <b>" + label + "</b>: <color=yellow>" + text + "</color>"); return; } string text2 = unit switch { "x" => $"{trace.BaseValue:F2}x", "%" => $"{trace.BaseValue * 100f:F0}%", "+%" => "0%", "m" => $"{trace.BaseValue:F2}m", _ => string.IsNullOrEmpty(unit) ? $"{trace.BaseValue:F1}" : $"{trace.BaseValue:F1} {unit}", }; sb.AppendLine(indent + "• <b>" + label + "</b>: <color=yellow>" + text + "</color> <i>(Base: " + text2 + ")</i>"); List<string> list = new List<string>(); foreach (var flatModifier in trace.FlatModifiers) { string item = flatModifier.Source; float item2 = flatModifier.Value; string arg = ((item2 >= 0f) ? "+" : ""); list.Add($"[Tier 1 Flat] {item}: {arg}{item2:F1}"); } foreach (var increasedModifier in trace.IncreasedModifiers) { string item3 = increasedModifier.Source; float item4 = increasedModifier.Value; string arg2 = ((item4 >= 0f) ? "+" : ""); if (flag) { list.Add($"[Tier 2 Efficiency] {item3}: {arg2}{item4 * 100f:F1}%"); } else { list.Add($"[Tier 2 Additive] {item3}: {arg2}{item4 * 100f:F1}%"); } } foreach (var (arg3, num) in trace.Multipliers) { list.Add($"[Tier 3 Multiplier] {arg3}: x{num:F2}"); } for (int i = 0; i < list.Count; i++) { string text3 = ((i == list.Count - 1) ? (indent + " <color=#A0A0A0>└─ ") : (indent + " <color=#A0A0A0>├─ ")); sb.AppendLine(text3 + list[i] + "</color>"); } } private static bool IsEfficiencyStat(CharacterStatType statType) { return CharacterStatManager.IsEfficiencyStat(statType); } private static List<string> GetResistanceSources(Player player, DamageType type) { //IL_0007: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); DamageType val = ToHitDataType(type); List<ItemData> equippedItems = CharacterStatsHelper.GetEquippedItems((Humanoid?)(object)player); for (int i = 0; i < equippedItems.Count; i++) { ItemData val2 = equippedItems[i]; if (val2?.m_shared?.m_damageModifiers == null) { continue; } foreach (DamageModPair damageModifier in val2.m_shared.m_damageModifiers) { if (damageModifier.m_type == val && (int)damageModifier.m_modifier != 0) { string text = val2.m_shared.m_name ?? "Gear"; if (text.StartsWith("$") && Localization.instance != null) { text = Localization.instance.Localize(text); } float num = EntityDefenseRegistry.ToFloatMultiplier(damageModifier.m_modifier); list.Add($"{text}: x{num:F2} ({damageModifier.m_modifier})"); } } } SEMan sEMan = ((Character)player).GetSEMan(); if (sEMan != null) { List<StatusEffect> statusEffects = sEMan.GetStatusEffects(); for (int j = 0; j < statusEffects.Count; j++) { StatusEffect obj = statusEffects[j]; SE_Stats val3 = (SE_Stats)(object)((obj is SE_Stats) ? obj : null); if (val3 == null || val3.m_mods == null) { continue; } foreach (DamageModPair mod in val3.m_mods) { if (mod.m_type == val && (int)mod.m_modifier != 0) { string text2 = ((StatusEffect)val3).m_name; if (string.IsNullOrEmpty(text2)) { text2 = ((Object)val3).name; } if (text2.StartsWith("$") && Localization.instance != null) { text2 = Localization.instance.Localize(text2); } float num2 = EntityDefenseRegistry.ToFloatMultiplier(mod.m_modifier); list.Add($"{text2}: x{num2:F2} ({mod.m_modifier})"); } } } } if (list.Count == 0) { list.Add("Innate Trait"); } return list; } private static DamageType ToHitDataType(DamageType type) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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) return (DamageType)(type switch { DamageType.Blunt => 1, DamageType.Slash => 2, DamageType.Pierce => 4, DamageType.Chop => 8, DamageType.Pickaxe => 16, DamageType.Fire => 32, DamageType.Frost => 64, DamageType.Lightning => 128, DamageType.Poison => 256, DamageType.Spirit => 512, _ => 31, }); } } [HarmonyPatch] public static class EnemyStaggerBar { private static readonly Dictionary<Character, GuiBar> _bars = new Dictionary<Character, GuiBar>(); private static FieldInfo? _mHudsField; private static FieldInfo? _mHealthFastField; private static FieldInfo? _mNameField; private static readonly Color AmberColor = new Color(0.96f, 0.62f, 0.04f); private static bool EnsureReflected() { if (_mHudsField == null) { _mHudsField = AccessTools.Field(typeof(EnemyHud), "m_huds"); } if (_mHealthFastField == null) { Type type = AccessTools.Inner(typeof(EnemyHud), "HudData"); if (type != null) { _mHealthFastField = AccessTools.Field(type, "m_healthFast"); } } if (_mNameField == null) { Type type2 = AccessTools.Inner(typeof(EnemyHud), "HudData"); if (type2 != null) { _mNameField = AccessTools.Field(type2, "m_name"); } } if (_mHudsField != null) { return _mHealthFastField != null; } return false; } [HarmonyPatch(typeof(EnemyHud), "ShowHud")] [HarmonyPostfix] public static void ShowHudPostfix(EnemyHud __instance, Character c, bool isMount) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.ModEnabled.Value || !ModConfig.StaggerOverhaulEnabled.Value || (Object)(object)c == (Object)null || (Object)(object)__instance == (Object)null || ModConfig.EnemyStaggerBarMode.Value == StaggerBarDisplayMode.Off || (ModConfig.EnemyStaggerBarMode.Value == StaggerBarDisplayMode.BossesOnly && !c.IsBoss()) || !EnsureReflected()) { return; } if (_bars.TryGetValue(c, out GuiBar value) && (Object)(object)value != (Object)null) { value.SetMaxValue(1f); value.m_smoothDrain = false; value.m_smoothFill = false; value.m_changeDelay = 0f; return; } try { IDictionary dictionary = (IDictionary)_mHudsField.GetValue(__instance); if (dictionary == null || !dictionary.Contains(c)) { return; } object obj = dictionary[c]; if (obj == null) { return; } GuiBar val = (GuiBar)_mHealthFastField.GetValue(obj); if (!((Object)(object)val == (Object)null)) { GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent); ((Object)val2).name = "vikinglib_stagger_bar"; RectTransform component = val2.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { float num = Mathf.Max(2.5f, component.sizeDelta.y * 0.35f); component.sizeDelta = new Vector2(component.sizeDelta.x, num); component.anchoredPosition = new Vector2(component.anchoredPosition.x, component.anchoredPosition.y - num - 1.5f); } GuiBar component2 = val2.GetComponent<GuiBar>(); if ((Object)(object)component2 != (Object)null) { component2.SetMaxValue(1f); component2.m_smoothDrain = false; component2.m_smoothFill = false; component2.m_changeDelay = 0f; component2.SetColor(AmberColor); component2.SetValue(0f); val2.SetActive(false); _bars[c] = component2; } } } catch (Exception ex) { ManualLogSource log = VikingLibPlugin.Log; if (log != null) { log.LogWarning((object)("[VikingLib EnemyStaggerBar] Failed to attach stagger bar for '" + ((Object)c).name + "': " + ex.Message)); } } } [HarmonyPatch(typeof(EnemyHud), "UpdateHuds")] [HarmonyPostfix] public static void UpdateHudsPostfix(EnemyHud __instance) { //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown if (!ModConfig.ModEnabled.Value || !ModConfig.StaggerOverhaulEnabled.Value || (Object)(object)__instance == (Object)null || _bars.Count == 0) { return; } StaggerBarDisplayMode value = ModConfig.EnemyStaggerBarMode.Value; List<Character> list = new List<Character>(); foreach (KeyValuePair<Character, GuiBar> bar in _bars) { Character key = bar.Key; GuiBar value2 = bar.Value; if ((Object)(object)key == (Object)null) { continue; } if ((Object)(object)value2 == (Object)null) { list.Add(key); continue; } if (value == StaggerBarDisplayMode.Off || (value == StaggerBarDisplayMode.BossesOnly && !key.IsBoss())) { if (((Component)value2).gameObject.activeSelf) { ((Component)value2).gameObject.SetActive(false); } continue; } float poisePercentage = StaggerManager.GetPoisePercentage(key); bool flag = key.IsStaggering() || StaggerManager.IsStaggering(key); if (poisePercentage > 0.001f || flag) { if (!((Component)value2).gameObject.activeSelf) { ((Component)value2).gameObject.SetActive(true); } if (flag) { float num = Mathf.PingPong(Time.time * 6f, 1f); value2.SetColor(Color.Lerp(AmberColor, Color.white, num)); float staggerFraction = StaggerManager.GetStaggerFraction(key); value2.SetValue(staggerFraction); if (!key.IsBoss() || !(_mHudsField != null)) { continue; } IDictionary dictionary = (IDictionary)_mHudsField.GetValue(__instance); if (dictionary == null || !dictionary.Contains(key)) { continue; } object obj = dictionary[key]; if (obj != null && _mNameField != null) { TextMeshProUGUI val = (TextMeshProUGUI)_mNameField.GetValue(obj); if ((Object)(object)val != (Object)null) { ((TMP_Text)val).text = Localization.instance.Localize(key.GetHoverName()) + " <color=#F59E0B>[STAGGERED]</color>"; } } } else { value2.SetColor(AmberColor); value2.SetValue(poisePercentage); } } else if (((Component)value2).gameObject.activeSelf) { ((Component)value2).gameObject.SetActive(false); } } for (int i = 0; i < list.Count; i++) { _bars.Remove(list[i]); } } [HarmonyPatch(typeof(EnemyHud), "RemoveCharacterHud")] [HarmonyPostfix] public static void RemoveCharacterHudPostfix(Character character) { if ((Object)(object)character != (Object)null) { _bars.Remove(character); } } } public struct StatusEffectDisplayData { public string EffectName; public string DisplayText; public string FallbackSymbol; public Sprite? Icon; public Color AccentColor; public Color BackgroundColor; } [HarmonyPatch] public static class EnemyStatusEffectsHud { private sealed class StatusEffectChip { public GameObject Root { get; } public RectTransform Rect { get; } public Image BackgroundImage { get; } public Image IconImage { get; } public TextMeshProUGUI ValueText { get; } public StatusEffectChip(GameObject root, RectTransform rect, Image bg, Image icon, TextMeshProUGUI text) { Root = root; Rect = rect; BackgroundImage = bg; IconImage = icon; ValueText = text; } public void Setup(StatusEffectDisplayData data) { //IL_0007: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) ((Graphic)BackgroundImage).color = data.BackgroundColor; if ((Object)(object)data.Icon != (Object)null) { ((Component)IconImage).gameObject.SetActive(true); IconImage.sprite = data.Icon; ((Graphic)IconImage).color = Color.white; ((TMP_Text)ValueText).text = data.DisplayText; ((Graphic)ValueText).color = data.AccentColor; } else { ((Component)IconImage).gameObject.SetActive(false); if (string.IsNullOrEmpty(data.DisplayText)) { ((TMP_Text)ValueText).text = data.FallbackSymbol; } else { ((TMP_Text)ValueText).text = data.FallbackSymbol + " " + data.DisplayText; } ((Graphic)ValueText).color = data.AccentColor; } } } private sealed class StatusEffectsHudContainer { public GameObject Root { get; } public RectTransform Rect { get; } public List<StatusEffectChip> Chips { get; } = new List<StatusEffectChip>(); public TMP_FontAsset? Font { get; set; } public StatusEffectsHudContainer(GameObject root, RectTransform rect, TMP_FontAsset? font) { Root = root; Rect = rect; Font = font; } } private static readonly Dictionary<Character, StatusEffectsHudContainer> _containers = new Dictionary<Character, StatusEffectsHudContainer>(); private static FieldInfo? _mHudsField; private static FieldInfo? _mHealthFastField; private static FieldInfo? _mHealthTextField; private static FieldInfo? _mNameField; private static Sprite? _chipBgSprite; private static bool EnsureReflected() { if (_mHudsField == null) { _mHudsField = AccessTools.Field(typeof(EnemyHud), "m_huds"); } if (_mHealthFastField == null) { Type type = AccessTools.Inner(typeof(EnemyHud), "HudData"); if (type != null) { _mHealthFastField = AccessTools.Field(type, "m_healthFast"); _mHealthTextField = AccessTools.Field(type, "m_healthText"); _mNameField = AccessTools.Field(type, "m_name"); } } if (_mHudsField != null) { return _mHealthFastField != null; } return false; } private static Sprite GetChipBackgroundSprite() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_chipBgSprite != (Object)null) { return _chipBgSprite; } try { Texture2D val = new Texture2D(16, 16, (TextureFormat)4, false); for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { float num = Mathf.Min(j, 15 - j); float num2 = Mathf.Min(i, 15 - i); float num3 = 0f; if (num < 3f && num2 < 3f) { num3 = Vector2.Distance(new Vector2(num, num2), new Vector2(3f, 3f)); } if (num3 > 3f) { val.SetPixel(j, i, Color.clear); continue; } float num4 = Mathf.Clamp01(3.5f - num3); val.SetPixel(j, i, new Color(1f, 1f, 1f, num4)); } } val.Apply(); _chipBgSprite = Sprite.Create(val, new Rect(0f, 0f, 16f, 16f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(4f, 4f, 4f, 4f)); } catch { _chipBgSprite = null; } return _chipBgSprite; } public static bool TryGetDisplayData(StatusEffect se, bool showText, out StatusEffectDisplayData data) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04dc: Unknown result type (might be due to invalid IL or missing references) //IL_04f7: Unknown result type (might be due to invalid IL or missing references) //IL_04fc: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0593: Unknown result type (might be due to invalid IL or missing references) //IL_0598: Unknown result type (might be due to invalid IL or missing references) //IL_05b3: Unknown result type (might be due to invalid IL or missing references) //IL_05b8: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_064f: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_066f: Unknown result type (might be due to invalid IL or missing references) //IL_0674: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_0722: Unknown result type (might be due to invalid IL or missing references) //IL_0727: Unknown result type (might be due to invalid IL or missing references) //IL_0742: Unknown result type (might be due to invalid IL or missing references) //IL_0747: Unknown result type (might be due to invalid IL or missing references) data = default(StatusEffectDisplayData); if (se == null || se.m_hidden || se.IsDone()) { return false; } if (se is VikingStatusEffect vikingStatusEffect) { string name = vikingStatusEffect.Definition.Name; if (string.Equals(name, "SE_Bleed", StringComparison.OrdinalIgnoreCase)) { data = new StatusEffectDisplayData { EffectName = "Bleed", DisplayText = (showText ? vikingStatusEffect.TotalSliceValue.ToString("F1") : string.Empty), FallbackSymbol = "\ud83e\ude78", Icon = ((StatusEffect)vikingStatusEffect).m_icon, AccentColor = new Color(0.94f, 0.27f, 0.27f), BackgroundColor = new Color(0.18f, 0.05f, 0.05f, 0.88f) }; return true; } if (string.Equals(name, "SE_Vulnerable", StringComparison.OrdinalIgnoreCase)) { data = new StatusEffectDisplayData { EffectName = "Vulnerable", DisplayText = (showText ? ((StatusEffect)vikingStatusEffect).GetIconText() : string.Empty), FallbackSymbol = "⚔", Icon = ((StatusEffect)vikingStatusEffect).m_icon, AccentColor = new Color(0.75f, 0.52f, 0.99f), BackgroundColor = new Color(0.12f, 0.04f, 0.18f, 0.88f) }; return true; } if (string.Equals(name, "SE_Cripple", StringComparison.OrdinalIgnoreCase)) { data = new StatusEffectDisplayData { EffectName = "Crippled", DisplayText = (showText ? ((StatusEffect)vikingStatusEffect).GetIconText() : string.Empty), FallbackSymbol = "\ud83e\uddb5", Icon = ((StatusEffect)vikingStatusEffect).m_icon, AccentColor = new Color(0.96f, 0.62f, 0.04f), BackgroundColor = new Color(0.18f, 0.11f, 0.03f, 0.88f) }; return true; } if (string.Equals(name, "SE_Ward", StringComparison.OrdinalIgnoreCase)) { data = new StatusEffectDisplayData { EffectName = "Ward", DisplayText = (showText ? ((StatusEffect)vikingStatusEffect).GetIconText() : string.Empty), FallbackSymbol = "\ud83d\udee1", Icon = ((StatusEffect)vikingStatusEffect).m_icon, AccentColor = new Color(0.22f, 0.74f, 0.97f), BackgroundColor = new Color(0.03f, 0.18f, 0.29f, 0.88f) }; return true; } if (string.Equals(name, "SE_EmpoweredStrike", StringComparison.OrdinalIgnoreCase)) { data = new StatusEffectDisplayData { EffectName = "Empowered", DisplayText = (showText ? ((StatusEffect)vikingStatusEffect).GetIconText() : string.Empty), FallbackSymbol = "⚡", Icon = ((StatusEffect)vikingStatusEffect).m_icon, AccentColor = new Color(0.98f, 0.75f, 0.14f), BackgroundColor = new Color(0.15f, 0.12f, 0.03f, 0.88f) }; return true; } string text = ((StatusEffect)vikingStatusEffect).GetIconText(); if (string.IsNullOrEmpty(text) && ((StatusEffect)vikingStatusEffect).m_ttl > 0f) { text = $"{Mathf.CeilToInt(((StatusEffect)vikingStatusEffect).GetRemaningTime())}s"; } data = new StatusEffectDisplayData { EffectName = vikingStatusEffect.Definition.DisplayName, DisplayText = (showText ? text : string.Empty), FallbackSymbol = ((name.Length >= 3) ? name.Substring(0, 3).ToUpper() : "FX"), Icon = ((StatusEffect)vikingStatusEffect).m_icon, AccentColor = new Color(0.89f, 0.91f, 0.94f), BackgroundColor = new Color(0.09f, 0.09f, 0.11f, 0.88f) }; return true; } string text2 = ((!string.IsNullOrEmpty(se.m_name)) ? se.m_name : (((Object)se).name ?? string.Empty)); string text3 = text2.ToLowerInvariant(); if (text3.IndexOf("burn", StringComparison.OrdinalIgnoreCase) >= 0) { data = new StatusEffectDisplayData { EffectName = "Burning", DisplayText = ((showText && se.m_ttl > 0f) ? $"{Mathf.CeilToInt(se.GetRemaningTime())}s" : string.Empty), FallbackSymbol = "\ud83d\udd25", Icon = se.m_icon, AccentColor = new Color(0.98f, 0.45f, 0.09f), BackgroundColor = new Color(0.18f, 0.08f, 0.03f, 0.88f) }; return true; } if (text3.IndexOf("poison", StringComparison.OrdinalIgnoreCase) >= 0) { data = new StatusEffectDisplayData { EffectName = "Poison", DisplayText = ((showText && se.m_ttl > 0f) ? $"{Mathf.CeilToInt(se.GetRemaningTime())}s" : string.Empty), FallbackSymbol = "☠", Icon = se.m_icon, AccentColor = new Color(0.13f, 0.77f, 0.37f), BackgroundColor = new Color(0.02f, 0.13f, 0.05f, 0.88f) }; return true; } if (text3.IndexOf("frost", StringComparison.OrdinalIgnoreCase) >= 0) { data = new StatusEffectDisplayData { EffectName = "Frost", DisplayText = ((showText && se.m_ttl > 0f) ? $"{Mathf.CeilToInt(se.GetRemaningTime())}s" : string.Empty), FallbackSymbol = "❄", Icon = se.m_icon, AccentColor = new Color(0.22f, 0.74f, 0.97f), BackgroundColor = new Color(0.02f, 0.1f, 0.15f, 0.88f) }; return true; } data = new StatusEffectDisplayData { EffectName = ((!string.IsNullOrEmpty(se.m_name)) ? se.m_name : text2), DisplayText = ((showText && se.m_ttl > 0f) ? $"{Mathf.CeilToInt(se.GetRemaningTime())}s" : string.Empty), FallbackSymbol = ((text2.Length >= 3) ? text2.Substring(0, 3).ToUpper() : "FX"), Icon = se.m_icon, AccentColor = new Color(0.89f, 0.91f, 0.94f), BackgroundColor = new Color(0.09f, 0.09f, 0.11f, 0.88f) }; return true; } [HarmonyPatch(typeof(EnemyHud), "ShowHud")] [HarmonyPostfix] public static void ShowHudPostfix(EnemyHud __instance, Character c, bool isMount) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_014e: 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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown if (!ModConfig.ModEnabled.Value || (Object)(object)c == (Object)null || (Object)(object)__instance == (Object)null || ModConfig.EnemyStatusEffectsMode.Value == StaggerBarDisplayMode.Off || (ModConfig.EnemyStatusEffectsMode.Value == StaggerBarDisplayMode.BossesOnly && !c.IsBoss()) || !EnsureReflected() || (_containers.TryGetValue(c, out StatusEffectsHudContainer value) && (Object)(object)value?.Root != (Object)null)) { return; } try { IDictionary dictionary = (IDictionary)_mHudsField.GetValue(__instance); if (dictionary == null || !dictionary.Contains(c)) { return; } object obj = dictionary[c]; if (obj == null) { return; } GuiBar val = (GuiBar)_mHealthFastField.GetValue(obj); if ((Object)(object)val == (Object)null) { return; } RectTransform component = ((Component)val).GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null) { return; } TMP_FontAsset val2 = null; if (_mHealthTextField != null) { TextMeshProUGUI val3 = (TextMeshProUGUI)_mHealthTextField.GetValue(obj); if ((Object)(object)val3 != (Object)null) { val2 = ((TMP_Text)val3).font; } } if ((Object)(object)val2 == (Object)null && _mNameField != null) { TextMeshProUGUI val4 = (TextMeshProUGUI)_mNameField.GetValue(obj); if ((Object)(object)val4 != (Object)null) { val2 = ((TMP_Text)val4).font; } } GameObject val5 = new GameObject("vikinglib_status_effects_root"); val5.transform.SetParent(((Component)val).transform.parent, false); RectTransform val6 = val5.AddComponent<RectTransform>(); val6.anchorMin = new Vector2(0.5f, 0f); val6.anchorMax = new Vector2(0.5f, 0f); val6.pivot = new Vector2(0.5f, 1f); val6.sizeDelta = new Vector2(component.sizeDelta.x, 18f); float num = 13f; val6.anchoredPosition = new Vector2(component.anchoredPosition.x, component.anchoredPosition.y - num); HorizontalLayoutGroup obj2 = val5.AddComponent<HorizontalLayoutGroup>(); ((LayoutGroup)obj2).childAlignment = (TextAnchor)4; ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 3f; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = false; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; StatusEffectsHudContainer value2 = new StatusEffectsHudContainer(val5, val6, val2); val5.SetActive(false); _containers[c] = value2; } catch (Exception ex) { ManualLogSource log = VikingLibPlugin.Log; if (log != null) { log.LogWarning((object)("[VikingLib EnemyStatusEffectsHud] Failed to attach status effect container for '" + ((Object)c).name + "': " + ex.Message)); } } } private static StatusEffectChip CreateChip(StatusEffectsHudContainer container) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("vikinglib_status_chip"); val.transform.SetParent(container.Root.transform, false); RectTransform val2 = val.AddComponent<RectTransform>(); val2.pivot = new Vector2(0.5f, 0.5f); Image val3 = val.AddComponent<Image>(); Sprite chipBackgroundSprite = GetChipBackgroundSprite(); if ((Object)(object)chipBackgroundSprite != (Object)null) { val3.sprite = chipBackgroundSprite; val3.type = (Type)1; } ContentSizeFitter obj = val.AddComponent<ContentSizeFitter>(); obj.horizontalFit = (FitMode)2; obj.verticalFit = (FitMode)2; HorizontalLayoutGroup obj2 = val.AddComponent<HorizontalLayoutGroup>(); ((LayoutGroup)obj2).padding = new RectOffset(4, 4, 1, 1); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 2f; ((LayoutGroup)obj2).childAlignment = (TextAnchor)4; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; GameObject val4 = new GameObject("Icon"); val4.transform.SetParent(val.transform, false); val4.AddComponent<RectTransform>(); Image icon = val4.AddComponent<Image>(); LayoutElement obj3 = val4.AddComponent<LayoutElement>(); obj3.preferredWidth = 13f; obj3.preferredHeight = 13f; obj3.minWidth = 13f; obj3.minHeight = 13f; GameObject val5 = new GameObject("Text"); val5.transform.SetParent(val.transform, false); val5.AddComponent<RectTransform>(); TextMeshProUGUI val6 = val5.AddComponent<TextMeshProUGUI>(); if ((Object)(object)container.Font != (Object)null) { ((TMP_Text)val6).font = container.Font; } ((TMP_Text)val6).fontSize = 10f; ((TMP_Text)val6).fontStyle = (FontStyles)1; ((TMP_Text)val6).alignment = (TextAlignmentOptions)514; ContentSizeFitter obj4 = val5.AddComponent<ContentSizeFitter>(); obj4.horizontalFit = (FitMode)2; obj4.verticalFit = (FitMode)2; return new StatusEffectChip(val, val2, val3, icon, val6); } [HarmonyPatch(typeof(EnemyHud), "UpdateHuds")] [HarmonyPostfix] public static void UpdateHudsPostfix(EnemyHud __instance) { if (!ModConfig.ModEnabled.Value || (Object)(object)__instance == (Object)null || _containers.Count == 0) { return; } StaggerBarDisplayMode value = ModConfig.EnemyStatusEffectsMode.Value; bool value2 = ModConfig.EnemyStatusEffectsShowText.Value; List<Character> list = new List<Character>(); foreach (KeyValuePair<Character, StatusEffectsHudContainer> container in _containers) { Character key = container.Key; StatusEffectsHudContainer value3 = container.Value; if ((Object)(object)key == (Object)null) { continue; } if (value3 == null || (Object)(object)value3.Root == (Object)null) { list.Add(key); continue; } if (value == StaggerBarDisplayMode.Off || (value == StaggerBarDisplayMode.BossesOnly && !key.IsBoss())) { if (value3.Root.activeSelf) { value3.Root.SetActive(false); } continue; } SEMan sEMan = key.GetSEMan(); List<StatusEffect> list2 = ((sEMan != null) ? sEMan.GetStatusEffects() : null); if (list2 == null || list2.Count == 0) { if (value3.Root.activeSelf) { value3.Root.SetActive(false); } continue; } int num = 0; for (int i = 0; i < list2.Count; i++) { if (TryGetDisplayData(list2[i], value2, out var data)) { if (num >= value3.Chips.Count) { StatusEffectChip item = CreateChip(value3); value3.Chips.Add(item); } StatusEffectChip statusEffectChip = value3.Chips[num]; statusEffectChip.Setup(data); if (!statusEffectChip.Root.activeSelf) { statusEffectChip.Root.SetActive(true); } num++; if (num >= 6) { break; } } } for (int j = num; j < value3.Chips.Count; j++) { if (value3.Chips[j].Root.activeSelf) { value3.Chips[j].Root.SetActive(false); } } if (num > 0) { if (!value3.Root.activeSelf) { value3.Root.SetActive(true); } } else if (value3.Root.activeSelf) { value3.Root.SetActive(false); } } for (int k = 0; k < list.Count; k++) { _containers.Remove(list[k]); } } [HarmonyPatch(typeof(EnemyHud), "RemoveCharacterHud")] [HarmonyPostfix] public static void RemoveCharacterHudPostfix(Character character) { if ((Object)(object)character != (Object)null && _containers.TryGetValue(character, out StatusEffectsHudContainer value)) { if ((Object)(object)value?.Root != (Object)null) { Object.Destroy((Object)(object)value.Root); } _containers.Remove(character); } } } } namespace VikingLib.UI.Tooltip { public class ItemTooltipContext { public static ItemTooltipContext? Current { get; internal set; } public ItemData Item { get; } public int QualityLevel { get; } public bool Crafting { get; } public float WorldLevel { get; } public Player? Player { get; } public ItemTooltipContext(ItemData item, int qualityLevel, bool crafting, float worldLevel, Player? player) { Item = item ?? throw new ArgumentNullException("item"); QualityLevel = qualityLevel; Crafting = crafting; WorldLevel = worldLevel; Player = player; } } public interface ITooltipSection { string SectionName { get; } int Priority { get; } bool ShouldRender(ItemTooltipContext context); string Render(ItemTooltipContext context); } public static class TooltipEngine { public delegate IEnumerable<string>? CustomTooltipLineProvider(ItemTooltipContext context); private sealed class PrioritizedLineProvider { public int Priority { get; } public CustomTooltipLineProvider Provider { get; } public PrioritizedLineProvider(int priority, CustomTooltipLineProvider provider) { Priority = priority; Provider = provider; } } private class AttackCardData { public string Title = ""; public string StepKey = ""; public Attack? NativeAttack; public float Cleave; public float Stamina; public float Eitr; public int Knockback; public float StaggerMultiplier; public string? OnHitStatusEffect; public float StatusEffectDuration; public Dictionary<DamageType, (float Min, float Max)> StepRanges = new Dictionary<DamageType, (float, float)>(); } private class StepGroup { public int StartStep; public int EndStep; } private static readonly List<ITooltipSection> _sections = new List<ITooltipSection>(); private static readonly List<PrioritizedLineProvider> _customLineProviders = new List<PrioritizedLineProvider>(); public static void RegisterSection(ITooltipSection section) { if (section != null) { _sections.Add(section); _sections.Sort((ITooltipSection a, ITooltipSection b) => a.Priority.CompareTo(b.Priority)); } } public static void RegisterLineProvider(CustomTooltipLineProvider provider, int priority = 100) { if (provider != null) { _customLineProviders.Add(new PrioritizedLineProvider(priority, provider)); _customLineProviders.Sort((PrioritizedLineProvider a, PrioritizedLineProvider b) => a.Priority.CompareTo(b.Priority)); } } public static void RegisterLineProvider(Func<ItemData?, Player?, IEnumerable<string>?> provider, int priority = 100) { if (provider != null) { RegisterLineProvider((ItemTooltipContext ctx) => provider(ctx.Item, ctx.Player), priority); } } public static bool IsWeaponOrTool(ItemData? item) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 if (item?.m_shared == null) { return false; } if ((int)item.m_shared.m_itemType == 5) { return false; } ItemType itemType = item.m_shared.m_itemType; if ((itemType - 3 <= 1 || (int)itemType == 14 || (int)itemType == 22) ? true : false) { return true; } itemType = item.m_shared.m_itemType; bool flag = (((int)itemType == 15 || (int)itemType == 19) ? true : false); if (flag && item.m_shared.m_attack != null && (((DamageTypes)(ref item.m_shared.m_damages)).GetTotalDamage() > 0f || item.m_shared.m_damages.m_chop > 0f || item.m_shared.m_damages.m_pickaxe > 0f)) { return true; } return false; } public static bool IsExpanded() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.TooltipExpandBehavior.Value == TooltipExpandBehavior.Toggle) { return ModConfig.IsTooltipToggleActive; } return Input.GetKey(ModConfig.TooltipExpandKey.Value); } public static string FormatFullTooltip(ItemData item, int qualityLevel, bool crafting, float worldLevel) { if (item?.m_shared == null) { return ""; } if (!IsExpanded()) { return FormatBaseWeaponTooltip(item, qualityLevel, crafting, worldLevel); } return FormatExtendedCombatDossier(item, qualityLevel, crafting, worldLevel); } private static string FormatBaseWeaponTooltip(ItemData item, int qualityLevel, bool crafting, float worldLevel) { //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); string description = item.m_shared.m_description; if (!string.IsNullOrEmpty(description)) { stringBuilder.Append(LocalizeSafe(description)); stringBuilder.Append("\n"); } if (item.m_shared.m_maxQuality > 1) { stringBuilder.Append($"\n$item_quality: <color=orange>{qualityLevel}</color>"); } stringBuilder.Append($"\n$item_weight: <color=orange>{item.GetWeight(-1):0.0}</color>"); if (!string.IsNullOrEmpty(item.m_crafterName)) { stringBuilder.Append("\n$item_crafter: <color=orange>" + item.m_crafterName + "</color>"); } float maxDurability = item.GetMaxDurability(qualityLevel); if (maxDurability > 0f) { if (crafting) { stringBuilder.Append($"\n$item_durability: <color=orange>{maxDurability:0}</color>"); } else { stringBuilder.Append($"\n$item_durability: <color=orange>{item.m_durability:0}/{maxDurability:0}</color>"); } } if (item.m_shared.m_canBeReparied && !crafting && (Object)(object)ObjectDB.instance != (Object)null) { Recipe recipe = ObjectDB.instance.GetRecipe(item); if ((Object)(object)recipe != (Object)null && recipe.m_minStationLevel > 0) { stringBuilder.Append($"\n$item_repairlevel: <color=orange>{recipe.m_minStationLevel}</color>"); } } float totalMin; if (Mathf.Abs(item.m_shared.m_movementModifier) > 0.001f) { totalMin = item.m_shared.m_movementModifier * 100f; string text = totalMin.ToString("+0;-0"); stringBuilder.Append("\n$item_movement_modifier: <color=orange>" + text + "%</color>"); } if ((Object)(object)item.m_shared.m_equipStatusEffect != (Object)null) { stringBuilder.Append("\n" + item.m_shared.m_equipStatusEffect.GetTooltipString()); } Character localPlayerSafe = (Character)(object)GetLocalPlayerSafe(); DamageTypes damage = item.GetDamage(qualityLevel, worldLevel); DamagePipeline.EvaluatePreviewDamages(localPlayerSafe, item, damage, item.m_shared.m_skillType, out Dictionary<DamageType, (float, float)> ranges, out totalMin, out float _); foreach (KeyValuePair<DamageType, (float, float)> item2 in ranges.Where<KeyValuePair<DamageType, (float, float)>>((KeyValuePair<DamageType, (float Min, float Max)> kvp) => kvp.Value.Min > 0.01f || kvp.Value.Max > 0.01f).ToList()) { string text2 = FormatRange(item2.Value.Item1, item2.Value.Item2); string localizedDamageType = GetLocalizedDamageType(item2.Key); string damageTypeColor = GetDamageTypeColor(item2.Key); stringBuilder.Append("\n" + localizedDamageType + ": <color=" + damageTypeColor + ">" + text2 + "</color>"); if (!ModConfig.StaggerOverhaulEnabled.Value) { continue; } if (item2.Key == DamageType.Slash) { float num = ModConfig.SlashBleedPercent.Value; if ((Object)(object)localPlayerSafe != (Object)null) { num += CharacterStatManager.GetStat(localPlayerSafe, CharacterStatType.SlashBleedPercent); } if (num > 0.001f) { float min = item2.Value.Item1 * num; float max = item2.Value.Item2 * num; string text3 = FormatRange(min, max); stringBuilder.Append("\n <color=#B91C1C>Bleed: +" + text3 + "</color>"); } } else if (item2.Key == DamageType.Blunt) { float num2 = item.m_shared.m_attack?.m_staggerMultiplier ?? 1f; if ((Object)(object)localPlayerSafe != (Object)null) { num2 *= CharacterStatManager.GetStat(localPlayerSafe, CharacterStatType.StaggerDamage); } float min2 = item2.Value.Item1 * num2; float max2 = item2.Value.Item2 * num2; string text4 = FormatRange(min2, max2); stringBuilder.Append("\n <color=#F59E0B>Stagger: " + text4 + "</color>"); } } string keyLabel = GetKeyLabel(ModConfig.TooltipExpandKey.Value); string text5 = ((ModConfig.TooltipExpandBehavior.Value == TooltipExpandBehavior.Toggle) ? "Press" : "Hold"); stringBuilder.Append("\n\n<color=#888888>[" + keyLabel + "] " + text5 + ": Combat Details</color>"); ItemTooltipContext context = new ItemTooltipContext(item, qualityLevel, crafting, worldLevel, GetLocalPlayerSafe()); foreach (ITooltipSection section in _sections) { if (section.ShouldRender(context)) { string text6 = section.Render(context); if (!string.IsNullOrEmpty(text6)) { stringBuilder.Append("\n" + text6); } } } return LocalizeSafe(stringBuilder.ToString()); } private static string FormatExtendedCombatDossier(ItemData item, int qualityLevel, bool crafting, float worldLevel) { //IL_0016: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Invalid comparison between Unknown and I4 //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Invalid comparison between Unknown and I4 //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Invalid comparison between Unknown and I4 //IL_099a: Unknown result type (might be due to invalid IL or missing references) //IL_09a0: Invalid comparison between Unknown and I4 //IL_0ba3: Unknown result type (might be due to invalid IL or missing references) //IL_0ba9: Invalid comparison between Unknown and I4 //IL_0b72: Unknown result type (might be due to invalid IL or missing references) //IL_0b78: Invalid comparison between Unknown and I4 //IL_0bb1: Unknown result type (might be due to invalid IL or missing references) //IL_0bb7: Invalid comparison between Unknown and I4 //IL_0b81: Unknown result type (might be due to invalid IL or missing references) //IL_0b87: Invalid comparison between Unknown and I4 //IL_0bbf: Unknown result type (might be due to invalid IL or missing references) //IL_0bc6: Invalid comparison between Unknown and I4 //IL_0dc3: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); Character localPlayerSafe = (Character)(object)GetLocalPlayerSafe(); WeaponAttackProfile profile = WeaponAttackRegistry.GetProfile(item); DamageTypes damage = item.GetDamage(qualityLevel, worldLevel); int num = Math.Max(1, profile.PrimaryChainLength); List<DamageType> activeCombatTypes = GetActiveCombatTypes(damage); List<StepGroup> list = GroupPrimarySteps(profile, num, activeCombatTypes); List<AttackCardData> list2 = new List<AttackCardData>(); float totalMax; float totalMin; foreach (StepGroup item2 in list) { string stepKey = $"primary_{item2.StartStep}"; string title = ((item2.StartStep != item2.EndStep) ? $"Hit {item2.StartStep} - {item2.EndStep}" : ((num == 1) ? "Primary Attack" : ((item2.StartStep == num) ? $"Hit {item2.StartStep} (Combo Finisher)" : $"Hit {item2.StartStep}"))); DamagePipeline.EvaluatePreviewDamages(localPlayerSafe, item, damage, item.m_shared.m_skillType, out Dictionary<DamageType, (float, float)> ranges, out totalMax, out totalMin, stepKey); Attack attack = item.m_shared.m_attack; float num2 = ((attack != null && attack.m_forceMultiplier > 0.01f) ? attack.m_forceMultiplier : 1f); float staggerMultiplier = ((attack != null && attack.m_staggerMultiplier > 0.01f) ? attack.m_staggerMultiplier : 1f); float num3 = attack?.m_attackStamina ?? 0f; float stamina = ((num3 > 0f && (Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetEffectiveWeaponAttackCost(num3, localPlayerSafe, item, isSecondaryAttack: false, CharacterStatType.AttackStaminaEfficiency) : num3); float num4 = attack?.m_attackEitr ?? 0f; float eitr = ((num4 > 0f && (Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetEffectiveWeaponAttackCost(num4, localPlayerSafe, item, isSecondaryAttack: false, CharacterStatType.AttackEitrEfficiency) : num4); AttackStepModifiers step = profile.GetStep(stepKey); list2.Add(new AttackCardData { Title = title, StepKey = stepKey, NativeAttack = attack, Cleave = step.Cleave, Stamina = stamina, Eitr = eitr, Knockback = Mathf.RoundToInt(item.m_shared.m_attackForce * num2), StaggerMultiplier = staggerMultiplier, OnHitStatusEffect = step.OnHitStatusEffect, StatusEffectDuration = step.StatusEffectDuration, StepRanges = ranges }); } if (profile.HasSecondary && item.HaveSecondaryAttack()) { DamagePipeline.EvaluatePreviewDamages(localPlayerSafe, item, damage, item.m_shared.m_skillType, out Dictionary<DamageType, (float, float)> ranges2, out totalMin, out totalMax, "secondary"); Attack secondaryAttack = item.m_shared.m_secondaryAttack; float num5 = ((secondaryAttack.m_forceMultiplier > 0.01f) ? secondaryAttack.m_forceMultiplier : 1f); float staggerMultiplier2 = ((secondaryAttack.m_staggerMultiplier > 0.01f) ? secondaryAttack.m_staggerMultiplier : 1f); float attackStamina = secondaryAttack.m_attackStamina; float stamina2 = ((attackStamina > 0f && (Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetEffectiveWeaponAttackCost(attackStamina, localPlayerSafe, item, isSecondaryAttack: true, CharacterStatType.AttackStaminaEfficiency) : attackStamina); float attackEitr = secondaryAttack.m_attackEitr; float eitr2 = ((attackEitr > 0f && (Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetEffectiveWeaponAttackCost(attackEitr, localPlayerSafe, item, isSecondaryAttack: true, CharacterStatType.AttackEitrEfficiency) : attackEitr); AttackStepModifiers step2 = profile.GetStep("secondary"); list2.Add(new AttackCardData { Title = "Secondary Attack", StepKey = "secondary", NativeAttack = secondaryAttack, Cleave = step2.Cleave, Stamina = stamina2, Eitr = eitr2, Knockback = Mathf.RoundToInt(item.m_shared.m_attackForce * num5), StaggerMultiplier = staggerMultiplier2, OnHitStatusEffect = step2.OnHitStatusEffect, StatusEffectDuration = step2.StatusEffectDuration, StepRanges = ranges2 }); } AttackCardData attackCardData = list2[0]; stringBuilder.Append("<size=85%>"); stringBuilder.Append("<color=#FFAA00><b>Common Properties:</b></color>"); ItemType itemType = item.m_shared.m_itemType; bool flag = (((int)itemType == 4 || (int)itemType == 14 || (int)itemType == 22) ? true : false); string text = (flag ? "$item_twohanded" : "$item_onehanded"); stringBuilder.Append("\nType: <color=#C0C0C0>" + text + "</color>"); float blockPower = item.GetBlockPower((float)qualityLevel); float timedBlockBonus = item.m_shared.m_timedBlockBonus; float num6 = blockPower * timedBlockBonus; float backstabBonus = item.m_shared.m_backstabBonus; if (blockPower > 0f) { stringBuilder.Append($"\n$item_blockarmor: <color=orange>{blockPower:0}</color>"); if (timedBlockBonus > 1f) { stringBuilder.Append($"\n$item_parrybonus: <color=orange>{timedBlockBonus:F1}x</color> (<color=yellow>{num6:0}</color>)"); } } if (backstabBonus > 1f) { float num7 = backstabBonus / 2f; stringBuilder.Append($"\n$item_backstab: <color=orange>{num7:F1}x</color>"); } if ((Object)(object)item.m_shared.m_equipStatusEffect != (Object)null) { stringBuilder.Append("\nBuff: <color=orange>" + item.m_shared.m_equipStatusEffect.m_name + "</color>"); } if (!string.IsNullOrEmpty(attackCardData.OnHitStatusEffect)) { VikingStatusEffectDefinition definition = StatusEffectRegistry.GetDefinition(attackCardData.OnHitStatusEffect); string arg = ((!string.IsNullOrEmpty(definition?.DisplayName)) ? definition.DisplayName : attackCardData.OnHitStatusEffect); stringBuilder.Append($"\nInflicts: <color=yellow>{arg}</color> ({attackCardData.StatusEffectDuration:0.#}s)"); } List<KeyValuePair<DamageType, (float, float)>> list3 = attackCardData.StepRanges.Where((KeyValuePair<DamageType, (float Min, float Max)> kvp) => kvp.Value.Min > 0.01f || kvp.Value.Max > 0.01f).ToList(); if (list3.Count > 0) { string text2 = ((num <= 1) ? "Damage" : ((list[0].EndStep > 1) ? $"Damage (Hit 1 - {list[0].EndStep})" : "Damage (Hit 1)")); if (list3.Count == 1) { KeyValuePair<DamageType, (float, float)> keyValuePair = list3[0]; string text3 = FormatRange(keyValuePair.Value.Item1, keyValuePair.Value.Item2); string localizedDamageType = GetLocalizedDamageType(keyValuePair.Key); string damageTypeColor = GetDamageTypeColor(keyValuePair.Key); stringBuilder.Append("\n" + text2 + ": <color=" + damageTypeColor + ">" + text3 + "</color> (" + localizedDamageType + ")"); if (ModConfig.StaggerOverhaulEnabled.Value) { if (keyValuePair.Key == DamageType.Slash) { float num8 = ModConfig.SlashBleedPercent.Value + (((Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetStat(localPlayerSafe, CharacterStatType.SlashBleedPercent) : 0f); if (num8 > 0.001f) { string text4 = FormatRange(keyValuePair.Value.Item1 * num8, keyValuePair.Value.Item2 * num8); stringBuilder.Append("\n <color=#B91C1C>Bleed: +" + text4 + "</color>"); } } else if (keyValuePair.Key == DamageType.Blunt) { float num9 = (item.m_shared.m_attack?.m_staggerMultiplier ?? 1f) * (((Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetStat(localPlayerSafe, CharacterStatType.StaggerDamage) : 1f); string text5 = FormatRange(keyValuePair.Value.Item1 * num9, keyValuePair.Value.Item2 * num9); stringBuilder.Append("\n <color=#F59E0B>Stagger: " + text5 + "</color>"); } } } else { stringBuilder.Append("\n" + text2 + ":"); foreach (KeyValuePair<DamageType, (float, float)> item3 in list3) { string text6 = FormatRange(item3.Value.Item1, item3.Value.Item2); string localizedDamageType2 = GetLocalizedDamageType(item3.Key); string damageTypeColor2 = GetDamageTypeColor(item3.Key); stringBuilder.Append("\n " + localizedDamageType2 + ": <color=" + damageTypeColor2 + ">" + text6 + "</color>"); if (!ModConfig.StaggerOverhaulEnabled.Value) { continue; } if (item3.Key == DamageType.Slash) { float num10 = ModConfig.SlashBleedPercent.Value + (((Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetStat(localPlayerSafe, CharacterStatType.SlashBleedPercent) : 0f); if (num10 > 0.001f) { string text7 = FormatRange(item3.Value.Item1 * num10, item3.Value.Item2 * num10); stringBuilder.Append("\n <color=#B91C1C>Bleed: +" + text7 + "</color>"); } } else if (item3.Key == DamageType.Blunt) { float num11 = (item.m_shared.m_attack?.m_staggerMultiplier ?? 1f) * (((Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetStat(localPlayerSafe, CharacterStatType.StaggerDamage) : 1f); string text8 = FormatRange(item3.Value.Item1 * num11, item3.Value.Item2 * num11); stringBuilder.Append("\n <color=#F59E0B>Stagger: " + text8 + "</color>"); } } } } if ((int)item.m_shared.m_itemType == 4 && item.m_shared.m_attack != null) { Attack attack2 = item.m_shared.m_attack; if (attack2.m_drawDurationMin > 0f) { float num12 = (((Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetStat(localPlayerSafe, CharacterStatType.BowDrawSpeed) : 1f); float num13 = attack2.m_drawDurationMin / Mathf.Max(0.01f, num12); stringBuilder.Append($"\nDraw Time: <color=yellow>{num13:0.0}s</color>"); } if (attack2.m_drawStaminaDrain > 0f) { float num14 = (((Object)(object)localPlayerSafe != (Object)null) ? CharacterStatManager.GetEffectiveActionCost(attack2.m_drawStaminaDrain, localPlayerSafe, CharacterStatType.BowDrawStaminaEfficiency) : attack2.m_drawStaminaDrain); stringBuilder.Append($"\nHold Stamina: <color=yellow>{num14:0}/s</color>"); } if (attack2.m_projectileVel > 0f) { stringBuilder.Append($"\nVelocity: <color=yellow>{attack2.m_projectileVel:0}</color>"); } } Attack attack3 = item.m_shared.m_attack; if (atta