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 Oathbound v0.21.7
BepInEx/plugins/WarriorRpg/Warrior.Core.dll
Decompiled 2 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Warrior.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+75524a93b33122b85192c86102f300b04ef67a8e")] [assembly: AssemblyProduct("Warrior.Core")] [assembly: AssemblyTitle("Warrior.Core")] [assembly: AssemblyVersion("1.0.0.0")] [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 Warrior.Core { public static class MartialTrees { private static readonly TreeWeb.Node[] BerserkerNodes = new TreeWeb.Node[25] { new TreeWeb.Node("b_grip", "Twin Grip", "Paired-axe attacks cost 3% less stamina. Berserker combat talents require paired axes in hand.", "Flint", Bonus.AttackCost, 0.03f), new TreeWeb.Node("b_edge", "Keen Edges", "Paired axes deal 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("b_breath", "Fighting Breath", "While wielding paired axes, normal stamina regeneration is 4% faster.", "MeadStaminaMinor", Bonus.Regen, 0.04f), new TreeWeb.Node("b_hone", "Honed Edges", "Paired axes deal another 4% more damage.", "Iron", Bonus.Damage, 0.04f), new TreeWeb.Node("b_frenzy", "Frenzy", "Every third paired-axe hit on the same enemy critically hits for 35% extra damage. Land each hit within 8 seconds; changing targets resets the chain.", "TrophyBoar"), new TreeWeb.Node("b_control", "Controlled Grip", "Paired-axe attacks cost another 3% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.03f), new TreeWeb.Node("b_weight", "Weighted Blades", "Paired-axe hits cause 6% more stagger.", "Copper", Bonus.FistStagger, 0.06f), new TreeWeb.Node("b_pace", "Measured Pace", "Paired-axe attacks cost another 4% less stamina.", "Bronze", Bonus.AttackCost, 0.04f), new TreeWeb.Node("b_rend", "Rend", "A paired-axe hit wounds its enemy for 6 seconds: 20% of the hit, capped at 12 bleed damage. Once every 8 seconds; wounds do not stack.", "Bloodbag"), new TreeWeb.Node("b_brace", "Braced Stance", "While wielding paired axes, take 5% less stagger buildup.", "HelmetLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("b_drive", "Driving Blades", "Paired-axe hits cause another 5% more stagger.", "Iron", Bonus.FistStagger, 0.05f), new TreeWeb.Node("b_rooted", "Rooted Stance", "While wielding paired axes, take another 5% less stagger buildup.", "ArmorLeatherLegs", Bonus.Stagger, 0.05f), new TreeWeb.Node("b_impact", "Axe Rush", "Starting a dodge primes your next paired-axe hit within 5 seconds with strong knockback. Once every 8 seconds; large enemies resist through normal mass.", "HelmetTrollLeather"), new TreeWeb.Node("b_step", "Sidestep", "While wielding paired axes, dodging costs 5% less stamina.", "DeerHide", Bonus.Dodge, 0.05f), new TreeWeb.Node("b_stride", "Long Stride", "While wielding paired axes, running costs 5% less stamina.", "CapeDeerHide", Bonus.Run, 0.05f), new TreeWeb.Node("b_ready", "Ready Footwork", "While wielding paired axes, dodging costs another 5% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.05f), new TreeWeb.Node("b_counter", "Countercut", "A dodge primes your next paired-axe hit within 5 seconds to restore 8 stamina. Once every 10 seconds. Missing does not consume it.", "MeadStaminaMedium"), new TreeWeb.Node("b_recover", "Battle Hardened", "Gain 5 maximum health while this class is active. Adds to food bonuses; does not refill health.", "MeadHealthMinor", Bonus.MaximumHealth, 5f), new TreeWeb.Node("b_lungs", "Deep Breath", "Gain 5 maximum stamina while this class is active. Adds to food bonuses; does not refill stamina.", "MeadStaminaMinor", Bonus.MaximumStamina, 5f), new TreeWeb.Node("b_resolve", "Firm Resolve", "While wielding paired axes, take another 5% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("b_blood", "Bloodsurge", "A paired-axe hit while below half health restores 3 health. Once every 12 seconds. Cannot revive you.", "MeadHealthMedium"), new TreeWeb.Node("b_roam", "Relentless Stride", "While wielding paired axes, running costs another 5% less stamina.", "CapeWolf", Bonus.Run, 0.05f), new TreeWeb.Node("b_spring", "Spring Step", "While wielding paired axes, jumping costs 10% less stamina.", "CapeFeather", Bonus.Jump, 0.1f), new TreeWeb.Node("b_force", "Heavy Hands", "Paired-axe hits cause another 5% more stagger.", "Iron", Bonus.FistStagger, 0.05f), new TreeWeb.Node("b_whirl", "Whirlwind", "Spin with both axes. Up to five enemies within 3.5 metres take 30 slash with heavy stagger and knockback. Requires paired axes. 35 stamina, every 15 seconds.", "TrophySkeleton") }; private static readonly TreeWeb.Lane[] BerserkerLanes = new TreeWeb.Lane[12] { new TreeWeb.Lane("b_whirl", "Storm of Axes", new TreeWeb.Node("b_whirl_wide", "Wider Arc", "Whirlwind reaches another metre.", "AxeIron"), new TreeWeb.Node("b_whirl_edge", "Storm Edges", "Whirlwind deals 30% more damage.", "Iron"), new TreeWeb.Node("b_whirl_swift", "Quick Recovery", "Whirlwind's cooldown falls from 15 to 11 seconds.", "LeatherScraps"), new TreeWeb.Node("b_whirl_blood", "Red Harvest", "Every enemy Whirlwind strikes is wounded for 6 seconds: 20% of the hit, capped at 12 bleed damage. Wounds refresh instead of stacking.", "Bloodbag")), new TreeWeb.Lane("b_whirl", "Reaver", new TreeWeb.Node("b_reave_grip", "Reaver's Grip", "Paired-axe attacks cost another 2% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.02f), new TreeWeb.Node("b_reave_edge", "Reaver's Edge", "Paired axes deal another 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("b_reave_force", "Reaver's Weight", "Paired-axe hits cause another 5% more stagger.", "Copper", Bonus.FistStagger, 0.05f), new TreeWeb.Node("b_cleave", "Cleave", "Every third same-target paired-axe hit also strikes one visible enemy within 3m for 30% of the hit, capped at 10 damage. Eight-second cooldown; cannot chain.", "TrophySkeleton")), new TreeWeb.Lane("b_frenzy", "Bloodlust", new TreeWeb.Node("b_fren_deep", "Rising Fury", "Frenzy's critical hit deals 55% extra damage instead of 35%.", "Iron"), new TreeWeb.Node("b_fren_hold", "Long Rage", "Frenzy's chain holds for 12 seconds between hits instead of 8.", "TrophyBoar"), new TreeWeb.Node("b_fren_edge", "Bloodied Edges", "Paired axes deal another 2% more damage.", "Bronze", Bonus.Damage, 0.02f), new TreeWeb.Node("b_fren_carry", "Unbroken Frenzy", "Your chain no longer resets when you change enemies. Only the chain window can break it.", "AxeIron")), new TreeWeb.Lane("b_frenzy", "Berserkergang", new TreeWeb.Node("b_gang_grip", "Wrapped Grips", "Paired-axe attacks cost another 2% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.02f), new TreeWeb.Node("b_gang_hide", "Scarred Hide", "While wielding paired axes, gain 3 armour.", "ArmorLeatherChest", Bonus.Armour, 3f), new TreeWeb.Node("b_gang_wind", "Wolf's Breath", "While wielding paired axes, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("b_gang_rage", "Berserkergang", "While below half health your paired-axe attacks deal 20% more damage and cause double stagger.", "TrophyWolf")), new TreeWeb.Lane("b_rend", "Butcher", new TreeWeb.Node("b_rend_deep", "Deep Rend", "Rend's wound is capped at 18 instead of 12.", "Bloodbag"), new TreeWeb.Node("b_rend_quick", "Quick Rend", "Rend's cooldown falls from 8 to 6 seconds.", "Flint"), new TreeWeb.Node("b_rend_edge", "Serrated Heads", "Paired axes deal another 2% more damage.", "Iron", Bonus.Damage, 0.02f), new TreeWeb.Node("b_rend_long", "Slow Wound", "Rend's wound runs four seconds longer at the same rate: five ticks instead of three.", "Bloodbag"), new TreeWeb.Node("b_rend_scent", "Blood in the Water", "Your paired-axe hits on an enemy already bleeding from Rend deal 15% more damage.", "WolfFang")), new TreeWeb.Lane("b_rend", "Gore", new TreeWeb.Node("b_gore_edge", "Gutting Edge", "Paired axes deal another 2% more damage.", "Bronze", Bonus.Damage, 0.02f), new TreeWeb.Node("b_gore_weight", "Cleaving Weight", "Paired-axe hits cause another 5% more stagger.", "Copper", Bonus.FistStagger, 0.05f), new TreeWeb.Node("b_gore_heart", "Hot Blood", "While wielding paired axes, normal health regeneration is 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("b_gore_feast", "Feast", "Killing an enemy that is bleeding from Rend restores 12 health and readies Rend at once. Once every 15 seconds.", "RawMeat")), new TreeWeb.Lane("b_impact", "Avalanche", new TreeWeb.Node("b_rush_force", "Full Weight", "Axe Rush's knockback is half again as strong.", "Stone"), new TreeWeb.Node("b_rush_quick", "Short Wind-up", "Axe Rush's cooldown falls from 8 to 6 seconds.", "ArmorLeatherLegs"), new TreeWeb.Node("b_rush_drive", "Driving Shoulder", "Paired-axe hits cause another 5% more stagger.", "Iron", Bonus.FistStagger, 0.05f), new TreeWeb.Node("b_rush_wave", "Avalanche", "Axe Rush also throws back every other enemy within 3 metres of the one you hit. Large enemies resist through their mass.", "TrophyGreydwarf")), new TreeWeb.Lane("b_impact", "Ironbark", new TreeWeb.Node("b_bark_hide", "Boiled Hide", "While wielding paired axes, gain 2 armour.", "ArmorLeatherChest", Bonus.Armour, 2f), new TreeWeb.Node("b_bark_jaw", "Set Jaw", "While wielding paired axes, take another 3% less stagger buildup.", "HelmetLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("b_bark_lungs", "Deep Lungs", "While wielding paired axes, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("b_bark_scar", "Scar Tissue", "While wielding paired axes, gain 1 armour for every tenth of your maximum health that is missing, up to 6.", "WolfPelt")), new TreeWeb.Lane("b_counter", "Counterblow", new TreeWeb.Node("b_cnt_deep", "Deep Draught", "Countercut restores 16 stamina instead of 8.", "MeadStaminaMedium"), new TreeWeb.Node("b_cnt_quick", "Quick Turn", "Countercut's cooldown falls from 10 to 7 seconds.", "Flint"), new TreeWeb.Node("b_cnt_roll", "Turning Shoulders", "While wielding paired axes, dodging costs another 3% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.03f), new TreeWeb.Node("b_cnt_answer", "Answer in Kind", "The Countercut hit also deals 30% more damage and cannot be blocked.", "AxeIron")), new TreeWeb.Lane("b_counter", "Skirmisher", new TreeWeb.Node("b_skir_step", "Loose Feet", "While wielding paired axes, dodging costs another 3% less stamina.", "DeerHide", Bonus.Dodge, 0.03f), new TreeWeb.Node("b_skir_stride", "Loping Stride", "While wielding paired axes, running costs another 3% less stamina.", "CapeDeerHide", Bonus.Run, 0.03f), new TreeWeb.Node("b_skir_leap", "Spring Heels", "While wielding paired axes, jumping costs another 5% less stamina.", "CapeFeather", Bonus.Jump, 0.05f), new TreeWeb.Node("b_skir_wind", "Fighting Wind", "Dodging while below half health restores 10 stamina. Once every 10 seconds.", "MeadStaminaMedium")), new TreeWeb.Lane("b_blood", "Lifeblood", new TreeWeb.Node("b_life_deep", "Deeper Draught", "Bloodsurge restores 8 health instead of 3.", "MeadHealthMedium"), new TreeWeb.Node("b_life_quick", "Quick Clotting", "Bloodsurge's cooldown falls from 12 to 8 seconds.", "Bloodbag"), new TreeWeb.Node("b_life_tide", "Rising Tide", "Bloodsurge triggers below 70% health instead of 50%.", "MeadHealthMinor"), new TreeWeb.Node("b_life_heart", "Strong Heart", "While wielding paired axes, normal health regeneration is another 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("b_life_pay", "Blood for Blood", "While below a quarter health, Bloodsurge heals twice as much and your paired-axe hits cannot be blocked.", "TrophyWolf")), new TreeWeb.Lane("b_blood", "Thick Blood", new TreeWeb.Node("b_thick_back", "Broad Back", "While wielding paired axes, gain 2 armour.", "ArmorLeatherChest", Bonus.Armour, 2f), new TreeWeb.Node("b_thick_gut", "Iron Gut", "While wielding paired axes, take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("b_thick_wind", "Bellows", "While wielding paired axes, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("b_thick_death", "Death Refuses", "Survive an enemy hit below 30% health to restore 10 health, and for 4 seconds your paired-axe attacks cost no stamina. Every 45 seconds.", "MeadHealthMedium")) }; private static readonly TreeWeb.Node[] BerserkerAll = TreeWeb.Flatten(BerserkerNodes, BerserkerLanes); private static readonly TreeWeb.Node[] BreakerNodes = new TreeWeb.Node[25] { new TreeWeb.Node("bk_grip", "Two-Handed Grip", "Two-handed axe attacks cost 3% less stamina. Breaker combat talents require a two-handed axe in hand.", "Wood", Bonus.AttackCost, 0.03f), new TreeWeb.Node("bk_edge", "Keen Edge", "Two-handed axes deal 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("bk_breath", "Fighting Breath", "While wielding a two-handed axe, normal stamina regeneration is 4% faster.", "MeadStaminaMinor", Bonus.Regen, 0.04f), new TreeWeb.Node("bk_hone", "Honed Edge", "Two-handed axes deal another 4% more damage.", "Iron", Bonus.Damage, 0.04f), new TreeWeb.Node("bk_fracture", "Fracture", "Each two-handed axe hit leaves a Fracture on that enemy, up to 4. Each adds 4% stagger buildup against it. They mend after 8 seconds.", "Flint"), new TreeWeb.Node("bk_control", "Controlled Grip", "Two-handed axe attacks cost another 3% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.03f), new TreeWeb.Node("bk_weight", "Weighted Head", "Two-handed axe hits cause 6% more stagger.", "Copper", Bonus.FistStagger, 0.06f), new TreeWeb.Node("bk_pace", "Measured Pace", "Two-handed axe attacks cost another 4% less stamina.", "Bronze", Bonus.AttackCost, 0.04f), new TreeWeb.Node("bk_shatter", "Shatter", "A two-handed axe hit on a staggered enemy spends every Fracture on it for 10% more damage each, then clears them.", "Battleaxe"), new TreeWeb.Node("bk_brace", "Braced Stance", "While wielding a two-handed axe, take 5% less stagger buildup.", "HelmetLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("bk_drive", "Driving Head", "Two-handed axe hits cause another 5% more stagger.", "Iron", Bonus.FistStagger, 0.05f), new TreeWeb.Node("bk_rooted", "Rooted Stance", "While wielding a two-handed axe, take another 5% less stagger buildup.", "ArmorLeatherLegs", Bonus.Stagger, 0.05f), new TreeWeb.Node("bk_quake", "Quake", "A two-handed axe hit on a staggered enemy leaves a Fracture on every other enemy within 4 metres.", "Stone"), new TreeWeb.Node("bk_step", "Sidestep", "While wielding a two-handed axe, dodging costs 5% less stamina.", "DeerHide", Bonus.Dodge, 0.05f), new TreeWeb.Node("bk_stride", "Long Stride", "While wielding a two-handed axe, running costs 5% less stamina.", "CapeDeerHide", Bonus.Run, 0.05f), new TreeWeb.Node("bk_ready", "Ready Footwork", "While wielding a two-handed axe, dodging costs another 5% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.05f), new TreeWeb.Node("bk_anvil", "Anvil", "While wielding a two-handed axe, take 10% less stagger buildup and 5% less damage from everything.", "HelmetIron"), new TreeWeb.Node("bk_recover", "Battle Hardened", "Gain 5 maximum health while this class is active. Adds to food bonuses; does not refill health.", "MeadHealthMinor", Bonus.MaximumHealth, 5f), new TreeWeb.Node("bk_lungs", "Deep Breath", "Gain 5 maximum stamina while this class is active. Adds to food bonuses; does not refill stamina.", "MeadStaminaMinor", Bonus.MaximumStamina, 5f), new TreeWeb.Node("bk_roam", "Relentless Stride", "While wielding a two-handed axe, running costs another 5% less stamina.", "CapeWolf", Bonus.Run, 0.05f), new TreeWeb.Node("bk_endure", "Long Work", "A two-handed axe kill restores 4 health and 6 stamina. Once every 8 seconds.", "MeadHealthMedium"), new TreeWeb.Node("bk_force", "Heavy Hands", "Two-handed axe hits cause another 5% more stagger.", "Iron", Bonus.FistStagger, 0.05f), new TreeWeb.Node("bk_march", "Breaker's March", "Armour weighs on you 40% less: that share of the movement penalty from your equipped armour is ignored.", "ArmorIronLegs", Bonus.Burden, 0.4f), new TreeWeb.Node("bk_resolve", "Firm Resolve", "While wielding a two-handed axe, take another 5% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("bk_sunder", "Sunder", "Drive the axe into the ground. Up to 6 enemies within 8 metres take 22 blunt, are staggered, thrown back and left with 3 Fractures. 35 stamina, every 45s.", "Stone") }; private static readonly TreeWeb.Lane[] BreakerLanes = new TreeWeb.Lane[12] { new TreeWeb.Lane("bk_fracture", "Deep Cracks", new TreeWeb.Node("bk_frc_deep", "Deeper Cracks", "Each Fracture adds 6% stagger buildup instead of 4%.", "Flint"), new TreeWeb.Node("bk_frc_high", "Spiderweb", "An enemy holds 6 Fractures instead of 4.", "Crystal"), new TreeWeb.Node("bk_frc_hold", "Slow to Mend", "Fractures last 14 seconds instead of 8.", "Coal"), new TreeWeb.Node("bk_frc_wide", "Split Grain", "A two-handed axe hit also leaves a Fracture on one other enemy within 3 metres.", "AxeIron"), new TreeWeb.Node("bk_frc_first", "Hairline", "Your first two-handed axe hit on an unfractured enemy leaves 2 Fractures instead of 1.", "Stone")), new TreeWeb.Lane("bk_fracture", "Whetstone", new TreeWeb.Node("bk_wht_edge", "Whetted Edge", "Two-handed axes deal another 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("bk_wht_grip", "Wrapped Grip", "Two-handed axe attacks cost another 2% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.02f), new TreeWeb.Node("bk_wht_wind", "Whetstone Breath", "While wielding a two-handed axe, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("bk_wht_bite", "Bite", "A two-handed axe hit on an enemy at full health deals 20% more damage. Once every 6 seconds.", "BattleaxeCrystal")), new TreeWeb.Lane("bk_shatter", "Ruin", new TreeWeb.Node("bk_run_deep", "Deeper Ruin", "Shatter pays 15% per Fracture instead of 10%.", "Iron"), new TreeWeb.Node("bk_run_keep", "Lingering Ruin", "A Shatter leaves 2 Fractures behind instead of clearing them all.", "Coal"), new TreeWeb.Node("bk_run_deny", "Keep Them Down", "A staggered enemy you hit with a two-handed axe cannot regenerate health for 6 seconds.", "Bloodbag"), new TreeWeb.Node("bk_run_take", "Spoils of Ruin", "A Shatter restores 5 health and 8 stamina. Once every 8 seconds.", "MeadHealthMedium")), new TreeWeb.Lane("bk_shatter", "Cleaver", new TreeWeb.Node("bk_clv_edge", "Cleaver's Edge", "Two-handed axes deal another 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("bk_clv_weight", "Cleaver's Weight", "Two-handed axe hits cause another 5% more stagger.", "Copper", Bonus.FistStagger, 0.05f), new TreeWeb.Node("bk_clv_grip", "Cleaver's Grip", "Two-handed axe attacks cost another 2% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.02f), new TreeWeb.Node("bk_clv_wide", "Wide Swing", "A two-handed axe hit on a staggered enemy also strikes one other enemy within 3 metres for 30% of the hit, capped at 12. Every 8 seconds.", "AxeIron")), new TreeWeb.Lane("bk_quake", "Aftershock", new TreeWeb.Node("bk_aft_push", "Full Weight", "Two-handed axe hits on a staggered enemy throw it back hard.", "Stone"), new TreeWeb.Node("bk_aft_wave", "Ground Gives", "A two-handed axe hit that staggers an enemy throws back everything within 3 metres. Every 10 seconds; large enemies resist.", "MaceIron"), new TreeWeb.Node("bk_aft_drive", "Driving Shoulder", "Two-handed axe hits cause another 5% more stagger.", "Iron", Bonus.FistStagger, 0.05f), new TreeWeb.Node("bk_aft_reach", "Wider Quake", "Quake reaches 6 metres instead of 4.", "CapeLox"), new TreeWeb.Node("bk_aft_crack", "Crack the Ground", "An enemy you throw back with a two-handed axe is left with 2 Fractures.", "Obsidian")), new TreeWeb.Lane("bk_quake", "Footing", new TreeWeb.Node("bk_ftg_step", "Loose Feet", "While wielding a two-handed axe, dodging costs another 3% less stamina.", "DeerHide", Bonus.Dodge, 0.03f), new TreeWeb.Node("bk_ftg_stride", "Loping Stride", "While wielding a two-handed axe, running costs another 3% less stamina.", "CapeDeerHide", Bonus.Run, 0.03f), new TreeWeb.Node("bk_ftg_grip", "Sure Hands", "Two-handed axe attacks cost another 2% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.02f), new TreeWeb.Node("bk_ftg_wind", "Second Wind", "While three or more enemies stand within 8 metres, your two-handed axe attacks cost 15% less stamina.", "MeadStaminaMedium")), new TreeWeb.Lane("bk_anvil", "Immovable", new TreeWeb.Node("bk_imv_hide", "Scarred Hide", "While wielding a two-handed axe, gain 3 armour.", "ArmorLeatherChest", Bonus.Armour, 3f), new TreeWeb.Node("bk_imv_gut", "Braced Gut", "While wielding a two-handed axe, take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("bk_imv_deep", "Deeper Anvil", "Anvil's damage reduction rises from 5% to 9%.", "HelmetIron"), new TreeWeb.Node("bk_imv_scar", "Scar Tissue", "While wielding a two-handed axe, gain 1 armour for every tenth of your maximum health that is missing, up to 6.", "WolfPelt")), new TreeWeb.Lane("bk_anvil", "Ironshod", new TreeWeb.Node("bk_irn_shod", "Ironshod", "Armour weighs on you another 40% less. With Breaker's March, four-fifths of the penalty is gone.", "ArmorIronChest", Bonus.Burden, 0.4f), new TreeWeb.Node("bk_irn_back", "Broad Back", "While wielding a two-handed axe, gain 2 armour.", "ArmorLeatherChest", Bonus.Armour, 2f), new TreeWeb.Node("bk_irn_leap", "Spring Heels", "While wielding a two-handed axe, jumping costs 5% less stamina.", "CapeFeather", Bonus.Jump, 0.05f), new TreeWeb.Node("bk_irn_hold", "Unmoved", "While wielding a two-handed axe, nothing smaller than a troll can throw you back.", "ArmorIronLegs")), new TreeWeb.Lane("bk_endure", "Steady Work", new TreeWeb.Node("bk_stw_deep", "Deeper Draught", "Long Work restores 10 health and 14 stamina instead of 4 and 6.", "MeadHealthMedium"), new TreeWeb.Node("bk_stw_quick", "Quick Recovery", "Long Work's cooldown falls from 8 seconds to 5.", "Flint"), new TreeWeb.Node("bk_stw_heart", "Hot Blood", "While wielding a two-handed axe, normal health regeneration is 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("bk_stw_hard", "Hard Labour", "While wielding a two-handed axe, take another 5% less damage from everything.", "HelmetDrake")), new TreeWeb.Lane("bk_endure", "Thick Hide", new TreeWeb.Node("bk_thk_bone", "Braced Bones", "While wielding a two-handed axe, take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("bk_thk_wind", "Steady Breath", "While wielding a two-handed axe, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("bk_thk_skin", "Thick Skin", "While wielding a two-handed axe, gain 2 armour.", "ArmorLeatherChest", Bonus.Armour, 2f), new TreeWeb.Node("bk_thk_death", "Death Refuses", "Survive an enemy hit below 30% health to restore 10 health, and for 4 seconds your two-handed axe attacks cost no stamina. Every 45 seconds.", "MeadHealthMedium")), new TreeWeb.Lane("bk_sunder", "Tremor", new TreeWeb.Node("bk_trm_wide", "Wider Tremor", "Sunder reaches 12 metres instead of 8.", "CapeLox"), new TreeWeb.Node("bk_trm_deep", "Deep Tremor", "Sunder hits 30% harder and leaves 5 Fractures instead of 3.", "Obsidian"), new TreeWeb.Node("bk_trm_quick", "Second Blow", "Sunder's cooldown falls from 45 seconds to 32.", "MeadStaminaMedium"), new TreeWeb.Node("bk_trm_rout", "Rout", "Enemies thrown back by Sunder lose track of you for 4 seconds and cannot regenerate health for 8.", "TrophySkeleton")), new TreeWeb.Lane("bk_sunder", "Quarryman", new TreeWeb.Node("bk_qry_edge", "Quarryman's Edge", "Two-handed axes deal another 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("bk_qry_weight", "Quarryman's Weight", "Two-handed axe hits cause another 5% more stagger.", "Copper", Bonus.FistStagger, 0.05f), new TreeWeb.Node("bk_qry_wind", "Quarryman's Breath", "While wielding a two-handed axe, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("bk_qry_take", "Take What You Need", "A two-handed axe kill restores 8 stamina while you carry more than half your weight limit. Every 10 seconds.", "MeadStaminaMedium")) }; private static readonly TreeWeb.Node[] BreakerAll = TreeWeb.Flatten(BreakerNodes, BreakerLanes); private static readonly TreeWeb.Node[] HighlanderNodes = new TreeWeb.Node[25] { new TreeWeb.Node("hl_grip", "Two-Handed Grip", "Two-handed sword attacks cost 3% less stamina. Highlander combat talents require a two-handed sword in hand.", "Wood", Bonus.AttackCost, 0.03f), new TreeWeb.Node("hl_edge", "Keen Edge", "Two-handed swords deal 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("hl_weight", "Weighted Blade", "Two-handed sword hits cause 6% more stagger.", "Copper", Bonus.FistStagger, 0.06f), new TreeWeb.Node("hl_hone", "Honed Edge", "Two-handed swords deal another 4% more damage.", "Iron", Bonus.Damage, 0.04f), new TreeWeb.Node("hl_execute", "Execution", "A two-handed sword hit below 30% health deals 60% extra, and finishes outright below 10%. A boss cannot be finished and takes 25% instead. Every 6 seconds.", "THSwordKrom"), new TreeWeb.Node("hl_control", "Controlled Grip", "Two-handed sword attacks cost another 3% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.03f), new TreeWeb.Node("hl_breath", "Fighting Breath", "While wielding a two-handed sword, normal stamina regeneration is 4% faster.", "MeadStaminaMinor", Bonus.Regen, 0.04f), new TreeWeb.Node("hl_pace", "Measured Pace", "Two-handed sword attacks cost another 4% less stamina.", "Bronze", Bonus.AttackCost, 0.04f), new TreeWeb.Node("hl_heft", "Heft", "A two-handed sword hit landed at least 2 seconds after your last attack is a measured blow: 40% extra damage and double stagger.", "TrophyBoar"), new TreeWeb.Node("hl_brace", "Braced Stance", "While wielding a two-handed sword, take 5% less stagger buildup.", "HelmetLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("hl_drive", "Driving Blade", "Two-handed sword hits cause another 5% more stagger.", "Iron", Bonus.FistStagger, 0.05f), new TreeWeb.Node("hl_temper", "Tempered Steel", "Two-handed swords deal another 2% more damage.", "Iron", Bonus.Damage, 0.02f), new TreeWeb.Node("hl_mortal", "Mortal Wound", "A two-handed sword hit marks the enemy for 10 seconds: it stops regenerating, takes 10% more from you, and its Execution line rises 5 points. Every 8 seconds.", "Bloodbag"), new TreeWeb.Node("hl_rooted", "Rooted Stance", "While wielding a two-handed sword, take another 5% less stagger buildup.", "ArmorLeatherLegs", Bonus.Stagger, 0.05f), new TreeWeb.Node("hl_force", "Heavy Hands", "Two-handed sword hits cause another 5% more stagger.", "Iron", Bonus.FistStagger, 0.05f), new TreeWeb.Node("hl_poise", "Sure Footing", "While wielding a two-handed sword, take another 5% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("hl_break", "Break Them Open", "A two-handed sword hit on a staggered enemy deals 35% extra damage and restores 8 stamina. Once every 6 seconds.", "MaceIron"), new TreeWeb.Node("hl_recover", "Battle Hardened", "Gain 5 maximum health while this class is active. Adds to food bonuses; does not refill health.", "MeadHealthMinor", Bonus.MaximumHealth, 5f), new TreeWeb.Node("hl_lungs", "Deep Breath", "Gain 5 maximum stamina while this class is active. Adds to food bonuses; does not refill stamina.", "MeadStaminaMinor", Bonus.MaximumStamina, 5f), new TreeWeb.Node("hl_step", "Sidestep", "While wielding a two-handed sword, dodging costs 5% less stamina.", "DeerHide", Bonus.Dodge, 0.05f), new TreeWeb.Node("hl_resolve", "Grim Resolve", "Four seconds without dodging sets your stance: gain 3 armour and take 10% less stagger buildup until you dodge again. Requires a two-handed sword in hand.", "ArmorIronChest"), new TreeWeb.Node("hl_stride", "Long Stride", "While wielding a two-handed sword, running costs 5% less stamina.", "CapeDeerHide", Bonus.Run, 0.05f), new TreeWeb.Node("hl_ready", "Ready Footwork", "While wielding a two-handed sword, dodging costs another 5% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.05f), new TreeWeb.Node("hl_bear", "Bear the Weight", "Armour weighs on you 40% less: that share of the movement penalty from your equipped armour is ignored.", "ArmorIronLegs", Bonus.Burden, 0.4f), new TreeWeb.Node("hl_headsman", "The Headsman's Swing", "Drop the greatsword on one enemy within 4 metres: 45 slash, heavy stagger. Doubles below 35% health, finishes below 15%. 40 stamina, every 18 seconds.", "SwordMistwalker") }; private static readonly TreeWeb.Lane[] HighlanderLanes = new TreeWeb.Lane[12] { new TreeWeb.Lane("hl_execute", "Headsman", new TreeWeb.Node("hl_exe_low", "Wider Mercy", "Execution triggers below 40% health instead of 30%.", "KnifeSilver"), new TreeWeb.Node("hl_exe_deep", "Heavier Blow", "Execution deals 90% extra damage instead of 60%.", "Iron"), new TreeWeb.Node("hl_exe_quick", "Practised Hand", "Execution's cooldown falls from 6 to 4 seconds.", "Flint"), new TreeWeb.Node("hl_exe_edge", "Headsman's Edge", "Two-handed swords deal another 2% more damage.", "Bronze", Bonus.Damage, 0.02f), new TreeWeb.Node("hl_exe_free", "No Second Blow", "Execution has no cooldown at all against an enemy already below 15% health. There is no waiting to finish something that is finished.", "SwordBlackmetal")), new TreeWeb.Lane("hl_execute", "Grim Harvest", new TreeWeb.Node("hl_har_heart", "Hot Blood", "While wielding a two-handed sword, normal health regeneration is 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("hl_har_take", "Blood Price", "An Execution restores 10 health and 15 stamina. Once every 10 seconds.", "MeadHealthMedium"), new TreeWeb.Node("hl_har_fear", "The Sight of It", "An Execution staggers every visible enemy within 5 metres.", "TrophySkeleton"), new TreeWeb.Node("hl_har_reap", "The Reaping", "An Execution also strikes every enemy within 6 metres that is itself below the Execution line, for 40% of the hit, capped at 20 each.", "SwordSilver")), new TreeWeb.Lane("hl_heft", "Measured", new TreeWeb.Node("hl_hft_deep", "Full Weight", "A measured blow deals 65% extra damage instead of 40%.", "Stone"), new TreeWeb.Node("hl_hft_quick", "Short Wind", "A measured blow needs 1.5 seconds since your last attack instead of 2.", "TrophyBoar"), new TreeWeb.Node("hl_hft_break", "Through the Guard", "A measured blow cannot be blocked.", "SwordIron"), new TreeWeb.Node("hl_hft_mark", "Splitting Blow", "A measured blow raises the enemy's Execution line by 10 points for 8 seconds.", "AtgeirIron")), new TreeWeb.Lane("hl_heft", "Long Reach", new TreeWeb.Node("hl_rch_grip", "Sure Grip", "Two-handed sword attacks cost another 2% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.02f), new TreeWeb.Node("hl_rch_far", "The Long Edge", "Two-handed sword hits on an enemy more than 2.5 metres away deal 12% more damage.", "SpearElderbark"), new TreeWeb.Node("hl_rch_wind", "Deep Lungs", "While wielding a two-handed sword, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("hl_rch_room", "Room to Swing", "While no enemy stands within 1.5 metres of you, two-handed sword attacks cost 20% less stamina.", "CapeDeerHide")), new TreeWeb.Lane("hl_mortal", "Hemorrhage", new TreeWeb.Node("hl_mor_long", "Lingering Wound", "A mortal wound lasts 16 seconds instead of 10.", "Bloodbag"), new TreeWeb.Node("hl_mor_quick", "Quick Work", "Mortal Wound's cooldown falls from 8 to 5 seconds.", "Flint"), new TreeWeb.Node("hl_mor_deep", "Deep Cut", "A mortally wounded enemy takes 18% more damage from you instead of 10%.", "KnifeCopper"), new TreeWeb.Node("hl_mor_edge", "Serrated Edge", "Two-handed swords deal another 2% more damage.", "Iron", Bonus.Damage, 0.02f), new TreeWeb.Node("hl_mor_low", "Marked for Death", "A mortal wound raises the enemy's Execution line by 15 points instead of 5.", "WolfFang")), new TreeWeb.Lane("hl_mortal", "Carver", new TreeWeb.Node("hl_crv_weight", "Cleaving Weight", "Two-handed sword hits cause another 5% more stagger.", "Copper", Bonus.FistStagger, 0.05f), new TreeWeb.Node("hl_crv_hide", "Scarred Hide", "While wielding a two-handed sword, gain 3 armour.", "ArmorLeatherChest", Bonus.Armour, 3f), new TreeWeb.Node("hl_crv_feast", "Butcher's Feast", "Killing a mortally wounded enemy restores 12 health and readies Mortal Wound at once. Once every 15 seconds.", "RawMeat"), new TreeWeb.Node("hl_crv_scar", "Scar Tissue", "While wielding a two-handed sword, gain 1 armour for every tenth of your maximum health that is missing, up to 6.", "WolfPelt")), new TreeWeb.Lane("hl_break", "Shatter", new TreeWeb.Node("hl_brk_deep", "Splitting Force", "Break Them Open deals 55% extra damage instead of 35%.", "MaceBronze"), new TreeWeb.Node("hl_brk_quick", "Quick Recovery", "Break Them Open's cooldown falls from 6 to 4 seconds.", "Flint"), new TreeWeb.Node("hl_brk_stam", "Second Wind", "Break Them Open restores 14 stamina instead of 8.", "MeadStaminaMedium"), new TreeWeb.Node("hl_brk_hold", "Keep Them Down", "Your two-handed sword hits on a staggered enemy that is also mortally wounded deal a further 20% extra damage.", "BattleaxeCrystal")), new TreeWeb.Lane("hl_break", "Ironbound", new TreeWeb.Node("hl_irn_back", "Broad Back", "While wielding a two-handed sword, gain 2 armour.", "ArmorLeatherChest", Bonus.Armour, 2f), new TreeWeb.Node("hl_irn_gut", "Iron Gut", "While wielding a two-handed sword, take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("hl_irn_bear", "Plated Stride", "Armour weighs on you another 40% less. With Bear the Weight, four-fifths of the penalty is gone.", "ArmorIronChest", Bonus.Burden, 0.4f), new TreeWeb.Node("hl_irn_stand", "Set Against It", "While Grim Resolve holds, enemy hits cannot push you back.", "ArmorIronLegs")), new TreeWeb.Lane("hl_resolve", "Unflinching", new TreeWeb.Node("hl_unf_deep", "Deeper Resolve", "Grim Resolve grants 6 armour instead of 3.", "ArmorIronChest"), new TreeWeb.Node("hl_unf_quick", "Settled Stance", "Grim Resolve sets after 2.5 seconds without dodging instead of 4.", "ArmorBronzeLegs"), new TreeWeb.Node("hl_unf_stand", "Unmoved", "While Grim Resolve holds you take no stagger buildup at all.", "HelmetIron"), new TreeWeb.Node("hl_unf_edge", "Planted Edge", "While Grim Resolve holds, your two-handed sword hits deal 10% more damage.", "SwordIron")), new TreeWeb.Lane("hl_resolve", "Last Rites", new TreeWeb.Node("hl_rit_heart", "Strong Heart", "While wielding a two-handed sword, normal health regeneration is another 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("hl_rit_gut", "Braced Bones", "While wielding a two-handed sword, take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("hl_rit_wind", "Steady Breath", "While wielding a two-handed sword, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("hl_rit_death", "Last Rites", "Survive an enemy hit below 30% health to restore 10 health, and for 4 seconds your two-handed sword attacks cost no stamina. Every 45 seconds.", "MeadHealthMedium")), new TreeWeb.Lane("hl_headsman", "The Block", new TreeWeb.Node("hl_hds_edge", "Sharpened Block", "The Headsman's Swing deals 40% more damage.", "Iron"), new TreeWeb.Node("hl_hds_quick", "Practised Drop", "The Headsman's Swing's cooldown falls from 18 to 13 seconds.", "LeatherScraps"), new TreeWeb.Node("hl_hds_low", "Clean Cut", "The Headsman's Swing finishes an enemy outright below 25% health instead of 15%.", "SwordBlackmetal"), new TreeWeb.Node("hl_hds_wide", "The Scaffold", "The Headsman's Swing also staggers every visible enemy within 4 metres of its target.", "TrophyGreydwarf")), new TreeWeb.Lane("hl_headsman", "Gravedigger", new TreeWeb.Node("hl_grv_edge", "Gravedigger's Edge", "Two-handed swords deal another 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("hl_grv_weight", "Gravedigger's Weight", "Two-handed sword hits cause another 5% more stagger.", "Copper", Bonus.FistStagger, 0.05f), new TreeWeb.Node("hl_grv_wind", "Gravedigger's Breath", "While wielding a two-handed sword, normal stamina regeneration is another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("hl_grv_toll", "The Toll", "A two-handed sword kill readies Execution at once and makes your next hit within 6 seconds a measured blow. Every 12 seconds; cannot chain.", "TrophySkeleton")) }; private static readonly TreeWeb.Node[] HighlanderAll = TreeWeb.Flatten(HighlanderNodes, HighlanderLanes); private static readonly TreeWeb.Node[] RogueNodes = new TreeWeb.Node[25] { new TreeWeb.Node("q_root", "Lightfoot", "Sneaking costs 5% less stamina.", "LeatherScraps", Bonus.Sneak, 0.05f), new TreeWeb.Node("q_shade", "Shade", "While crouched, enemies notice you from 5% closer.", "CapeTrollHide", Bonus.Stealth, 0.05f), new TreeWeb.Node("q_quiet", "Quiet Soles", "Make 10% less noise.", "DeerHide", Bonus.Noise, 0.1f), new TreeWeb.Node("q_edge", "Hidden Edge", "Melee attacks deal 4% more damage.", "KnifeFlint", Bonus.Damage, 0.04f), new TreeWeb.Node("q_ambush", "Ambush", "Your melee hit against an unalerted enemy deals 35% more damage. Once every 10 seconds.", "KnifeCopper"), new TreeWeb.Node("q_stalk", "Stalker", "Sneaking costs another 5% less stamina.", "CapeTrollHide", Bonus.Sneak, 0.05f), new TreeWeb.Node("q_reach", "Patient Hunter", "While crouched, enemies notice you from another 5% closer.", "GreydwarfEye", Bonus.Stealth, 0.05f), new TreeWeb.Node("q_cut", "Fine Edge", "Melee attacks deal another 3% more damage.", "KnifeCopper", Bonus.Damage, 0.03f), new TreeWeb.Node("q_vein", "Open Vein", "A melee hit from behind or against an unalerted enemy causes a 6-second bleed: 20% of the hit, capped at 12. Once every 8 seconds.", "Bloodbag"), new TreeWeb.Node("q_step", "Sidestep", "Dodging costs 5% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.05f), new TreeWeb.Node("q_stride", "Swift Feet", "Running costs 5% less stamina.", "CapeDeerHide", Bonus.Run, 0.05f), new TreeWeb.Node("q_balance", "Balance", "Take 5% less stagger buildup.", "HelmetLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("q_counter", "Counterstep", "Dodge, then land a melee hit within 5 seconds for 25% more damage. Once every 10 seconds.", "KnifeSilver"), new TreeWeb.Node("q_shadow", "Shadow Steps", "Make another 10% less noise.", "Feathers", Bonus.Noise, 0.1f), new TreeWeb.Node("q_breath", "Held Breath", "Stamina regenerates 3% faster.", "MeadStaminaMinor", Bonus.Regen, 0.03f), new TreeWeb.Node("q_crouch", "Low Profile", "Sneaking costs another 5% less stamina.", "LeatherScraps", Bonus.Sneak, 0.05f), new TreeWeb.Node("q_vanish", "Vanish", "Break away. Enemies within 30 metres lose you. For 6 seconds you are 50% better concealed and 75% quieter. 30 stamina, every 45 seconds.", "CapeTrollHide"), new TreeWeb.Node("q_escape", "Escape Route", "Running costs another 5% less stamina.", "CapeWolf", Bonus.Run, 0.05f), new TreeWeb.Node("q_roll", "Practised Roll", "Dodging costs another 5% less stamina.", "ArmorTrollLeatherLegs", Bonus.Dodge, 0.05f), new TreeWeb.Node("q_recover", "Survivor", "Gain 5 maximum health while this class is active. Adds to food bonuses; does not refill health.", "MeadHealthMinor", Bonus.MaximumHealth, 5f), new TreeWeb.Node("q_survive", "Narrow Escape", "Survive an enemy hit below 30% health to restore 4 health and 12 stamina. Once every 45 seconds; cannot save a lethal hit.", "MeadHealthMedium"), new TreeWeb.Node("q_leap", "Light Landing", "Jumping costs 10% less stamina.", "Feathers", Bonus.Jump, 0.1f), new TreeWeb.Node("q_poised", "Poised", "Take another 5% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("q_air", "Second Breath", "Gain 5 maximum stamina while this class is active. Adds to food bonuses; does not refill stamina.", "MeadStaminaMinor", Bonus.MaximumStamina, 5f), new TreeWeb.Node("q_fall", "Featherfall", "Absorb up to 20 fall damage once every 30 seconds. Larger falls can still hurt or kill you.", "CapeFeather") }; private static readonly TreeWeb.Node[] MonkNodes = new TreeWeb.Node[25] { new TreeWeb.Node("n_root", "Empty Hands", "Bare-fist attacks gain 5 blunt damage. Claws are the only weapons a Monk may equip, and never a shield. Armour and non-combat tools remain usable.", "TrophyBoar", Bonus.Fist, 5f), new TreeWeb.Node("n_knuckle", "Conditioned Knuckles", "Bare fists gain another 3 blunt damage.", "Stone", Bonus.Fist, 3f), new TreeWeb.Node("n_breath", "Measured Breath", "Stamina regenerates 3% faster.", "MeadStaminaMinor", Bonus.Regen, 0.03f), new TreeWeb.Node("n_form", "Economy of Motion", "Bare-fist attacks cost 5% less stamina.", "Flint", Bonus.AttackCost, 0.05f), new TreeWeb.Node("n_third", "Third Bell", "Every third bare-fist hit on the same enemy within 8 seconds deals 50% more damage and double stagger. Changing targets resets the sequence.", "Bronze"), new TreeWeb.Node("n_step", "Open Stance", "Dodging costs 5% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.05f), new TreeWeb.Node("n_stride", "Wind Step", "Running costs 5% less stamina.", "CapeDeerHide", Bonus.Run, 0.05f), new TreeWeb.Node("n_force", "Firm Palm", "Bare-fist attacks cause 12% more stagger.", "Stone", Bonus.FistStagger, 0.12f), new TreeWeb.Node("n_palm", "Driving Palm", "Dodge, then punch an enemy within 5 seconds to knock it back. Once every 8 seconds. Large enemies resist through their mass.", "TrophyGreydwarf"), new TreeWeb.Node("n_flow", "Flow", "Bare-fist attacks cost another 5% less stamina.", "Flint", Bonus.AttackCost, 0.05f), new TreeWeb.Node("n_spring", "Spring Step", "Jumping costs 10% less stamina.", "Feathers", Bonus.Jump, 0.1f), new TreeWeb.Node("n_still", "Still Mind", "Gain 5 maximum stamina while this class is active. Adds to food bonuses; does not refill stamina.", "MeadStaminaMinor", Bonus.MaximumStamina, 5f), new TreeWeb.Node("n_return", "Returning Breath", "Dodge, then land a bare-fist hit within 5 seconds to regain 10 stamina. Once every 10 seconds.", "MeadStaminaMedium"), new TreeWeb.Node("n_mend", "Vital Breath", "Gain 5 maximum health while this class is active. Adds to food bonuses; does not refill health.", "MeadHealthMinor", Bonus.MaximumHealth, 5f), new TreeWeb.Node("n_resolve", "Resolve", "Take 5% less stagger buildup.", "HelmetLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("n_body", "Conditioned Body", "Gain 3 armour.", "ArmorLeatherChest", Bonus.Armour, 3f), new TreeWeb.Node("n_clear", "Clear Mind", "Gather yourself on command. For 8 seconds your bare-fist attacks cost no stamina, deal 20% more damage and cause double stagger. 25 stamina, every 30 seconds.", "MeadHealthMedium"), new TreeWeb.Node("n_iron", "Iron Knuckles", "Bare fists gain another 2 blunt damage.", "Iron", Bonus.Fist, 2f), new TreeWeb.Node("n_poise", "Poise", "Take another 5% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.05f), new TreeWeb.Node("n_reach", "Firm Foundation", "Bare-fist attacks cause another 10% more stagger.", "Bronze", Bonus.FistStagger, 0.1f), new TreeWeb.Node("n_sweep", "Sweeping Palm", "Every third same-target punch also strikes one visible enemy within 3m for 35% of the punch, capped at 8 blunt damage. 8-second cooldown; cannot chain.", "TrophySkeleton"), new TreeWeb.Node("n_guard", "Open Guard", "Blocking with bare hands costs 10% less stamina.", "Stone", Bonus.Block, 0.1f), new TreeWeb.Node("n_patient", "Patient Guard", "Gain another 2 armour.", "ArmorLeatherChest", Bonus.Armour, 2f), new TreeWeb.Node("n_ready", "Ready Stance", "Dodging costs another 5% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.05f), new TreeWeb.Node("n_parry", "Iron Palm", "A successful bare-hand block restores 6 stamina and empowers your next punch within 5 seconds by 30%. Once every 10 seconds.", "Iron") }; private static readonly TreeWeb.Lane[] RogueLanes = new TreeWeb.Lane[12] { new TreeWeb.Lane("q_ambush", "Assassin", new TreeWeb.Node("q_amb_edge", "Killing Edge", "Ambush's opening strike deals 50% more damage instead of 35%.", "KnifeCopper"), new TreeWeb.Node("q_amb_quick", "No Second Chance", "Ambush's cooldown falls from 10 to 7 seconds.", "KnifeFlint"), new TreeWeb.Node("q_amb_cut", "Practised Cut", "Melee attacks deal another 3% more damage.", "Bronze", Bonus.Damage, 0.03f), new TreeWeb.Node("q_amb_mark", "Mark the Throat", "An Ambush strike marks its enemy for 8 seconds; your melee hits on the marked enemy deal 15% more damage. One mark at a time, and a new Ambush moves it.", "KnifeSilver")), new TreeWeb.Lane("q_ambush", "Prowler", new TreeWeb.Node("q_prowl_soft", "Soft Ground", "Sneaking costs another 4% less stamina.", "LeatherScraps", Bonus.Sneak, 0.04f), new TreeWeb.Node("q_prowl_dim", "Dim Figure", "While crouched, enemies notice you from another 4% closer.", "GreydwarfEye", Bonus.Stealth, 0.04f), new TreeWeb.Node("q_prowl_hush", "Hushed Step", "Make another 5% less noise.", "Feathers", Bonus.Noise, 0.05f), new TreeWeb.Node("q_prowl_unseen", "Never There", "A melee kill breaks contact: for 4 seconds you are 40% better concealed and 50% quieter. Once every 20 seconds.", "CapeTrollHide")), new TreeWeb.Lane("q_vein", "Bloodletter", new TreeWeb.Node("q_blood_deep", "Deep Cut", "Open Vein's wound is capped at 18 instead of 12.", "Bloodbag"), new TreeWeb.Node("q_blood_keen", "Serrated Edge", "Melee attacks deal another 2% more damage.", "KnifeCopper", Bonus.Damage, 0.02f), new TreeWeb.Node("q_blood_quick", "Quick Work", "Open Vein's cooldown falls from 8 to 6 seconds.", "KnifeFlint"), new TreeWeb.Node("q_blood_long", "Slow Bleed", "Open Vein's wound runs four seconds longer at the same rate: five ticks instead of three.", "Bloodbag"), new TreeWeb.Node("q_blood_hunt", "Scent of Blood", "Your melee hits on an enemy already bleeding from Open Vein deal 15% more damage.", "KnifeSilver")), new TreeWeb.Lane("q_vein", "Cutthroat", new TreeWeb.Node("q_cut_grip", "Reverse Grip", "Melee attacks deal another 3% more damage.", "KnifeFlint", Bonus.Damage, 0.03f), new TreeWeb.Node("q_cut_side", "Blindside", "While crouched, enemies notice you from another 3% closer.", "CapeTrollHide", Bonus.Stealth, 0.03f), new TreeWeb.Node("q_cut_breath", "Steady Hand", "Stamina regenerates another 2% faster.", "MeadStaminaMedium", Bonus.Regen, 0.02f), new TreeWeb.Node("q_cut_finish", "Finish It", "A melee hit on an enemy below 25% health deals 25% more damage. Once every 8 seconds.", "KnifeSilver")), new TreeWeb.Lane("q_counter", "Riposte", new TreeWeb.Node("q_rip_edge", "Sharper Answer", "Counterstep's empowered hit deals 40% more damage instead of 25%.", "KnifeCopper"), new TreeWeb.Node("q_rip_swift", "Quick Feet", "Counterstep's cooldown falls from 10 to 7 seconds.", "ArmorLeatherLegs"), new TreeWeb.Node("q_rip_roll", "Loose Roll", "Dodging costs another 3% less stamina.", "ArmorTrollLeatherLegs", Bonus.Dodge, 0.03f), new TreeWeb.Node("q_rip_twin", "Twin Answer", "Counterstep answers twice: the next two melee hits inside its window are both empowered.", "KnifeSilver")), new TreeWeb.Lane("q_counter", "Footpad", new TreeWeb.Node("q_foot_stride", "Fleet Stride", "Running costs another 3% less stamina.", "CapeDeerHide", Bonus.Run, 0.03f), new TreeWeb.Node("q_foot_poise", "Loose Shoulders", "Take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("q_foot_jump", "Light Feet", "Jumping costs another 5% less stamina.", "CapeFeather", Bonus.Jump, 0.05f), new TreeWeb.Node("q_foot_push", "Shoulder Check", "Dodge, then land a melee hit within 5 seconds to add a strong knockback impulse. Once every 12 seconds. Large enemies resist it through their normal mass.", "HelmetLeather")), new TreeWeb.Lane("q_vanish", "Vanishing Act", new TreeWeb.Node("q_van_deep", "Deeper Shadow", "Vanish conceals you for 3 seconds longer.", "CapeTrollHide"), new TreeWeb.Node("q_van_quiet", "Silent Tread", "Make another 5% less noise.", "Feathers", Bonus.Noise, 0.05f), new TreeWeb.Node("q_van_swift", "Quick Exit", "Vanish's cooldown falls from 45 to 35 seconds.", "ArmorTrollLeatherLegs"), new TreeWeb.Node("q_van_twin", "Second Shadow", "Vanish sells two openings instead of one: the first two melee hits inside its window each count as a hit on an unalerted enemy.", "KnifeSilver")), new TreeWeb.Lane("q_vanish", "Slipstream", new TreeWeb.Node("q_slip_roll", "Rolling Start", "Dodging costs another 3% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.03f), new TreeWeb.Node("q_slip_shade", "Dimmer Shade", "While crouched, enemies notice you from another 3% closer.", "GreydwarfEye", Bonus.Stealth, 0.03f), new TreeWeb.Node("q_slip_breath", "Even Breath", "Stamina regenerates another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("q_slip", "Slipaway", "Dodging grants 5 seconds of 30% better crouched concealment and 50% less noise. Once every 10 seconds. Enemies do not forget you automatically.", "CapeTrollHide")), new TreeWeb.Lane("q_survive", "Survivor", new TreeWeb.Node("q_surv_deep", "Second Wind", "Narrow Escape restores 8 health instead of 4.", "MeadHealthMedium"), new TreeWeb.Node("q_surv_swift", "Practised Escape", "Narrow Escape's cooldown falls from 45 to 30 seconds.", "CapeWolf"), new TreeWeb.Node("q_surv_heart", "Quiet Heart", "Normal health regeneration is 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("q_surv_wind", "Full Lungs", "Narrow Escape restores 20 stamina instead of 12.", "MeadStaminaMedium"), new TreeWeb.Node("q_surv_smoke", "Smoke and Mirrors", "Narrow Escape also breaks contact: enemies within 20 metres lose track of you, and for 4 seconds you are 40% better concealed and 50% quieter.", "CapeTrollHide")), new TreeWeb.Lane("q_survive", "Hardened", new TreeWeb.Node("q_hard_skin", "Toughened Leathers", "Gain 3 armour.", "ArmorLeatherChest", Bonus.Armour, 3f), new TreeWeb.Node("q_hard_grit", "Grit", "Take another 3% less stagger buildup.", "HelmetLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("q_hard_wind", "Long Wind", "Stamina regenerates another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("q_hard_corner", "Cornered", "While below 30% health your melee attacks deal 15% more damage and your dodges cost no stamina.", "MeadHealthMedium")), new TreeWeb.Lane("q_fall", "Freerunner", new TreeWeb.Node("q_free_light", "Lighter Landing", "Featherfall absorbs up to 30 fall damage instead of 20.", "CapeFeather"), new TreeWeb.Node("q_free_quick", "Quick Recovery", "Featherfall's cooldown falls from 30 to 20 seconds.", "ArmorTrollLeatherLegs"), new TreeWeb.Node("q_free_leap", "Long Leap", "Jumping costs another 5% less stamina.", "Feathers", Bonus.Jump, 0.05f), new TreeWeb.Node("q_free_roll", "Roll With It", "An absorbed fall becomes momentum: restore 15 stamina, and your next melee hit within 5 seconds deals 20% more damage.", "CapeLox")), new TreeWeb.Lane("q_fall", "Dropfall", new TreeWeb.Node("q_drop_leap", "Spring Loaded", "Jumping costs another 5% less stamina.", "CapeFeather", Bonus.Jump, 0.05f), new TreeWeb.Node("q_drop_poise", "Loose Knees", "Take another 3% less stagger buildup.", "ArmorLeatherLegs", Bonus.Stagger, 0.03f), new TreeWeb.Node("q_drop_quiet", "Quiet Landing", "Make another 5% less noise.", "DeerHide", Bonus.Noise, 0.05f), new TreeWeb.Node("q_drop_strike", "Falling Blade", "A melee hit landed while you are off the ground deals 30% more damage and counts as a hit on an unalerted enemy. Once every 10 seconds.", "KnifeSilver")) }; private static readonly TreeWeb.Lane[] MonkLanes = new TreeWeb.Lane[12] { new TreeWeb.Lane("n_third", "Cadence", new TreeWeb.Node("n_bell_deep", "Struck Bell", "Third Bell's hit deals 75% more damage instead of 50%.", "Bronze"), new TreeWeb.Node("n_bell_quick", "Quickening", "Third Bell's chain holds for 12 seconds between hits instead of 8.", "Flint"), new TreeWeb.Node("n_bell_knuck", "Seasoned Knuckles", "Bare fists gain another 2 blunt damage.", "Stone", Bonus.Fist, 2f), new TreeWeb.Node("n_bell_carry", "Carry the Rhythm", "Your combination no longer resets when you change enemies. Only the chain window can break it.", "TrophyBoar")), new TreeWeb.Lane("n_third", "Conditioning", new TreeWeb.Node("n_cond_wrap", "Wrapped Hands", "Bare-fist attacks cost another 3% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.03f), new TreeWeb.Node("n_cond_bone", "Bone Density", "Bare fists gain another 2 blunt damage.", "Iron", Bonus.Fist, 2f), new TreeWeb.Node("n_cond_wind", "Working Lungs", "Stamina regenerates another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("n_cond_break", "Break the Guard", "The third hit of your combination cannot be blocked.", "Iron")), new TreeWeb.Lane("n_palm", "Driving Force", new TreeWeb.Node("n_palm_force", "Full Extension", "Driving Palm's knockback is half again as strong.", "Stone"), new TreeWeb.Node("n_palm_quick", "Short Step", "Driving Palm's cooldown falls from 8 to 6 seconds.", "ArmorLeatherLegs"), new TreeWeb.Node("n_palm_stance", "Rooted Palm", "Bare-fist attacks cause another 5% more stagger.", "Bronze", Bonus.FistStagger, 0.05f), new TreeWeb.Node("n_palm_wave", "Shockpalm", "Driving Palm also throws back every other enemy within 3 metres of the one you hit. Large enemies resist through their mass.", "TrophyGreydwarf")), new TreeWeb.Lane("n_palm", "Wind Step", new TreeWeb.Node("n_wind_light", "Light Step", "Dodging costs another 3% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.03f), new TreeWeb.Node("n_wind_run", "Running Form", "Running costs another 5% less stamina.", "CapeDeerHide", Bonus.Run, 0.05f), new TreeWeb.Node("n_wind_leap", "High Step", "Jumping costs another 5% less stamina.", "CapeFeather", Bonus.Jump, 0.05f), new TreeWeb.Node("n_wind_crash", "Crashing Step", "Dodge, then land a bare-fist hit within 5 seconds and it lands as the third bell of your combination, whatever the count stood at. Once every 12 seconds.", "TrophySkeleton")), new TreeWeb.Lane("n_return", "Breathing", new TreeWeb.Node("n_ret_deep", "Deep Breath", "Returning Breath restores 18 stamina instead of 10.", "MeadStaminaMedium"), new TreeWeb.Node("n_ret_quick", "Even Tempo", "Returning Breath's cooldown falls from 10 to 7 seconds.", "Flint"), new TreeWeb.Node("n_ret_flow", "Unbroken Flow", "Bare-fist attacks cost another 3% less stamina.", "LeatherScraps", Bonus.AttackCost, 0.03f), new TreeWeb.Node("n_ret_calm", "Settled Lungs", "Stamina regenerates another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("n_ret_tireless", "Tireless", "The Returning Breath hit makes your bare-fist attacks cost no stamina for 4 seconds.", "MeadStaminaMedium")), new TreeWeb.Lane("n_return", "Current", new TreeWeb.Node("n_cur_step", "Flowing Step", "Dodging costs another 3% less stamina.", "DeerHide", Bonus.Dodge, 0.03f), new TreeWeb.Node("n_cur_poise", "Unmoved", "Take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("n_cur_hand", "Loose Hands", "Bare-fist attacks cost another 2% less stamina.", "Flint", Bonus.AttackCost, 0.02f), new TreeWeb.Node("n_cur_redirect", "Redirect", "A bare-fist hit landed within 5 seconds of taking an enemy hit deals 20% more damage. Once every 10 seconds.", "ArmorLeatherChest")), new TreeWeb.Lane("n_clear", "Clarity", new TreeWeb.Node("n_clear_long", "Held Breath", "Clear Mind lasts 3 seconds longer.", "MeadStaminaMedium"), new TreeWeb.Node("n_clear_level", "Level Head", "Take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("n_clear_swift", "Quick Settle", "Clear Mind's cooldown falls from 30 to 22 seconds.", "Flint"), new TreeWeb.Node("n_clear_force", "Rushing Palm", "While Clear Mind holds, every bare-fist hit adds a strong knockback impulse. Large enemies resist through their mass.", "TrophyGreydwarf")), new TreeWeb.Lane("n_clear", "Stillness", new TreeWeb.Node("n_calm_body", "Settled Body", "Gain another 2 armour.", "ArmorLeatherChest", Bonus.Armour, 2f), new TreeWeb.Node("n_calm_guard", "Soft Guard", "Blocking with bare hands costs another 5% less stamina.", "Stone", Bonus.Block, 0.05f), new TreeWeb.Node("n_calm_heart", "Quiet Heart", "Normal health regeneration is 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("n_calm", "Inner Calm", "Survive an enemy hit below 30% health to restore 6 health. Once every 45 seconds; cannot save a lethal hit.", "MeadHealthMedium")), new TreeWeb.Lane("n_sweep", "Wide Arc", new TreeWeb.Node("n_sweep_reach", "Longer Reach", "Sweeping Palm reaches 5 metres instead of 3.", "Bronze"), new TreeWeb.Node("n_sweep_hard", "Heavier Sweep", "Sweeping Palm's secondary hit is capped at 14 instead of 8.", "Iron"), new TreeWeb.Node("n_sweep_quick", "Quick Sweep", "Sweeping Palm's cooldown falls from 8 to 6 seconds.", "Flint"), new TreeWeb.Node("n_sweep_stagger", "Sweeping Force", "Bare-fist attacks cause another 5% more stagger.", "Stone", Bonus.FistStagger, 0.05f), new TreeWeb.Node("n_sweep_circle", "Circle Sweep", "Sweeping Palm strikes up to three nearby enemies instead of one.", "TrophySkeleton")), new TreeWeb.Lane("n_sweep", "Uprooting", new TreeWeb.Node("n_root_force", "Rooted Force", "Bare-fist attacks cause another 5% more stagger.", "Copper", Bonus.FistStagger, 0.05f), new TreeWeb.Node("n_root_poise", "Deep Root", "Take another 3% less stagger buildup.", "HelmetLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("n_root_wind", "Working Breath", "Stamina regenerates another 2% faster.", "MeadStaminaMinor", Bonus.Regen, 0.02f), new TreeWeb.Node("n_root_topple", "Topple", "Your bare-fist hit on an enemy that is already staggering deals 30% more damage and throws it back. Once every 8 seconds.", "TrophyGreydwarf")), new TreeWeb.Lane("n_parry", "Open Guard", new TreeWeb.Node("n_parry_deep", "Steady Guard", "Iron Palm restores 12 stamina instead of 6.", "MeadStaminaMedium"), new TreeWeb.Node("n_parry_quick", "Ready Hands", "Iron Palm's cooldown falls from 10 to 7 seconds.", "Flint"), new TreeWeb.Node("n_parry_block", "Softer Guard", "Blocking with bare hands costs another 5% less stamina.", "Stone", Bonus.Block, 0.05f), new TreeWeb.Node("n_parry_turn", "Turn the Blow", "A successful bare-hand block also throws the attacker back, along with anything else within 3 metres. Large enemies resist through their mass.", "Iron")), new TreeWeb.Lane("n_parry", "Unshakeable", new TreeWeb.Node("n_shake_arm", "Toughened Arms", "Gain another 2 armour.", "ArmorLeatherChest", Bonus.Armour, 2f), new TreeWeb.Node("n_shake_poise", "Unshakeable", "Take another 3% less stagger buildup.", "HelmetTrollLeather", Bonus.Stagger, 0.03f), new TreeWeb.Node("n_shake_heart", "Steady Heart", "Normal health regeneration is another 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("n_shake_stand", "Immovable", "While no enemy has hit you for 5 seconds, you take no stagger buildup at all.", "ArmorLeatherChest")) }; private static readonly TreeWeb.Node[] RogueAll = TreeWeb.Flatten(RogueNodes, RogueLanes); private static readonly TreeWeb.Node[] MonkAll = TreeWeb.Flatten(MonkNodes, MonkLanes); public static IReadOnlyList<Talent> Berserker { get; } = TreeWeb.Build(BerserkerNodes, BerserkerLanes); public static IReadOnlyList<ClassSpell> BreakerSpells { get; } = Array.AsReadOnly(new ClassSpell[1] { new ClassSpell("bk_sunder", "Sunder", "Stone", "drive the axe into the ground: up to 6 enemies near you take 22 blunt, and are staggered, thrown back and left fractured.", 0f, 45f, 22f, 6, SpellKind.Sunder, "breaker", 0f, 35f) }); public static IReadOnlyList<Talent> Breaker { get; } = TreeWeb.Build(BreakerNodes, BreakerLanes); public static IReadOnlyList<ClassSpell> HighlanderSpells { get; } = Array.AsReadOnly(new ClassSpell[1] { new ClassSpell("hl_headsman", "The Headsman's Swing", "SwordMistwalker", "bring your greatsword down on one enemy in front of you, finishing it if it is already failing.", 0f, 18f, 45f, 1, SpellKind.Behead, "highlander", 0f, 40f) }); public static IReadOnlyList<Talent> Highlander { get; } = TreeWeb.Build(HighlanderNodes, HighlanderLanes); public static IReadOnlyList<ClassSpell> RogueSpells { get; } = Array.AsReadOnly(new ClassSpell[1] { new ClassSpell("q_vanish", "Vanish", "CapeTrollHide", "break away: enemies within 30 metres lose track of you, and you move concealed and quiet for 6 seconds.", 0f, 45f, 0f, 1, SpellKind.Vanish, "rogue", 0f, 30f) }); public static IReadOnlyList<ClassSpell> MonkSpells { get; } = Array.AsReadOnly(new ClassSpell[1] { new ClassSpell("n_clear", "Clear Mind", "FistFenrirClaw", "for 8 seconds your bare fists cost no stamina, strike 20% harder and stagger twice as heavily.", 0f, 30f, 0f, 1, SpellKind.Focus, "monk", 0f, 25f) }); public static IReadOnlyList<ClassSpell> BerserkerSpells { get; } = Array.AsReadOnly(new ClassSpell[1] { new ClassSpell("b_whirl", "Whirlwind", "AxeIron", "spin with both axes, striking every visible enemy around you.", 0f, 15f, 30f, 5, SpellKind.Whirl, "berserker", 0f, 35f) }); public static IReadOnlyList<Talent> Rogue { get; } = TreeWeb.Build(RogueNodes, RogueLanes); public static IReadOnlyList<Talent> Monk { get; } = TreeWeb.Build(MonkNodes, MonkLanes); public static float Value(Progression state, Bonus bonus) { return TreeWeb.Value((state.ClassId == "rogue") ? RogueAll : ((state.ClassId == "monk") ? MonkAll : ((state.ClassId == "berserker") ? BerserkerAll : ((state.ClassId == "highlander") ? HighlanderAll : ((state.ClassId == "breaker") ? BreakerAll : Array.Empty<TreeWeb.Node>())))), state, bonus); } } public static class BloodMoon { public const int DefaultInterval = 7; public const int MinimumInterval = 2; public const int MaximumInterval = 99; public const float MinimumSenses = 1f; public const float MaximumSenses = 3f; public const float DefaultSenses = 1.6f; public const float MinimumStars = 1f; public const float MaximumStars = 10f; public const float DefaultStars = 2.5f; public const double NightOffset = 0.15; public const double SleepLockSeconds = 90.0; public static int Interval(int interval) { if (interval >= 2) { if (interval <= 99) { return interval; } return 99; } return 7; } public static float Senses(float multiplier) { return Clamp(multiplier, 1f, 3f); } public static float Stars(float multiplier) { return Clamp(multiplier, 1f, 10f); } private static float Clamp(float value, float low, float high) { if (!float.IsNaN(value)) { if (!(value < low)) { if (!(value > high)) { return value; } return high; } return low; } return low; } public static int NightIndex(double timeSeconds, double dayLengthSeconds) { if (dayLengthSeconds <= 0.0 || double.IsNaN(timeSeconds) || double.IsInfinity(timeSeconds) || double.IsNaN(dayLengthSeconds)) { return 0; } double num = Math.Floor((timeSeconds - dayLengthSeconds * 0.15) / dayLengthSeconds); if (!(num < -2147483648.0)) { if (!(num > 2147483647.0)) { return (int)num; } return int.MaxValue; } return int.MinValue; } public static bool IsNightFraction(double fraction) { if (double.IsNaN(fraction) || double.IsInfinity(fraction)) { return false; } fraction -= Math.Floor(fraction); if (!(fraction < 0.15)) { return fraction >= 0.85; } return true; } public static bool IsNight(double timeSeconds, double dayLengthSeconds) { if (dayLengthSeconds <= 0.0 || double.IsNaN(dayLengthSeconds) || double.IsInfinity(dayLengthSeconds) || double.IsNaN(timeSeconds) || double.IsInfinity(timeSeconds)) { return false; } return IsNightFraction(timeSeconds / dayLengthSeconds); } public static bool SleepLocked(double timeSeconds, double dayLengthSeconds) { double num = SecondsSinceMoonrise(timeSeconds, dayLengthSeconds); if (num >= 0.0) { return num < 90.0; } return false; } public static double SecondsSinceMoonrise(double timeSeconds, double dayLengthSeconds) { if (dayLengthSeconds <= 0.0 || double.IsNaN(dayLengthSeconds) || double.IsInfinity(dayLengthSeconds) || double.IsNaN(timeSeconds) || double.IsInfinity(timeSeconds)) { return -1.0; } double num = timeSeconds / dayLengthSeconds; num -= Math.Floor(num); if (double.IsNaN(num)) { return -1.0; } if (num >= 0.85) { return (num - 0.85) * dayLengthSeconds; } if (num < 0.15) { return (num + 0.15) * dayLengthSeconds; } return -1.0; } public static bool IsBlood(int nightIndex, int interval) { if (nightIndex > 0) { return nightIndex % Interval(interval) == 0; } return false; } public static int NightsUntil(int nightIndex, int interval) { int num = Interval(interval); int num2 = nightIndex % num; if (num2 != 0 || nightIndex <= 0) { return num - num2; } return 0; } } public sealed class ClassDefinition { public string Id { get; } public string Name { get; } public string Description { get; } public IReadOnlyList<string> Branches { get; } public IReadOnlyList<Talent> Talents { get; } public string UnlockRequirement { get; } public string Icon { get; } public ClassDefinition(string id, string name, string description, string[] branches, IReadOnlyList<Talent> talents, string unlockRequirement = "", string icon = "") { Id = id; Name = name; Description = description; Branches = Array.AsReadOnly((branches.Length == 0) ? branches : branches.Concat(new string[1] { "DEFENSE" }).ToArray()); Talents = ((branches.Length == 0) ? talents : DefenseTree.Append(id, talents, branches.Length)); UnlockRequirement = unlockRequirement; Icon = ((icon.Length > 0) ? icon : (talents.FirstOrDefault()?.Icon ?? "")); } public Talent? Find(string id) { return Talents.FirstOrDefault((Talent t) => t.Id == id); } } public static class Classes { public static IReadOnlyList<ClassDefinition> All { get; } = Array.AsReadOnly(new ClassDefinition[13] { new ClassDefinition("huscarl", "Huscarl", "A sworn household warrior. Master your weapons, punish openings and carry the fight forward.", new string[6] { "COUNTER", "BREAKER", "ADVANCE", "FOOTWORK", "COMPOSURE", "MASTERY" }, VikingTrees.Huscarl, "", "SwordIron"), new ClassDefinition("shieldbearer", "Shieldbearer", "Stand in the shield wall. Turn successful shield blocks into counters and protection for nearby allies. No bows.", new string[6] { "WALL", "COUNTER", "RALLY", "REBUKE", "RESOLVE", "SHELTER" }, VikingTrees.Shieldbearer, "", "ShieldBanded"), new ClassDefinition("valkyrie", "Valkyrie", "Rise above the battle. Strike from the air, reach the wounded and shield those who still fight. No bows.", new string[6] { "WINGS", "SKYSTRIKE", "DESCENT", "MERCY", "SPEAR", "WINDWARD" }, VikingTrees.Valkyrie, "", "SpearWolfFang"), new ClassDefinition("ranger", "Ranger", "Keep your distance. Place your shots. Find a path through the wilds. No metal armour.", new string[6] { "PRECISION", "BARBS", "IMPACT", "SKIRMISH", "HUNT", "TRAIL" }, RangerTree.Talents), new ClassDefinition("mage", "Mage", "Build your Eitr reserve. Unlock elemental spells at the ends of your branches. No metal armour.", new string[6] { "EMBER", "FROST", "STORM", "CINDERS", "RIME", "TEMPEST" }, MageTree.Talents, "", "StaffFireball"), new ClassDefinition("warlock", "Warlock", "Offer blood for protection. Bind the dead, drain enemies and weave curses. No metal armour.", new string[6] { "BLOOD", "BONE", "GRAVE", "HUNGER", "COVEN", "HEX" }, WarlockTree.Talents, "", "StaffShield"), new ClassDefinition("rogue", "Rogue", "Stealth, opening strikes and evasive footwork. One-handed weapons and the bow family, with the pickaxe kept for mining. No shields or metal armour.", new string[6] { "AMBUSH", "WOUNDS", "COUNTER", "SHADOW", "ESCAPE", "LANDING" }, MartialTrees.Rogue, "", "KnifeFlint"), new ClassDefinition("monk", "Monk", "Fight with bare fists or a claw, and gather bare-handed. Build combinations and turn defence into openings. No other weapons, shields or metal armour.", new string[6] { "COMBINATION", "PALM", "FLOW", "CALM", "SWEEP", "GUARD" }, MartialTrees.Monk, "", "FistFenrirClaw"), new ClassDefinition("hunter", "Hunter", "Fight alongside a permanent wolf companion. Call it back after death; strengthen your bond as you grow.", new string[6] { "FANGS", "PACK", "PURSUIT", "VIGOR", "CARE", "KINSHIP" }, HunterTree.Talents), new ClassDefinition("berserker", "Berserker", "Fight with paired axes, and carry a single axe or pickaxe to gather. Build brutal combinations and turn evasions into counterattacks.", new string[6] { "FRENZY", "REND", "IMPACT", "COUNTER", "BLOOD", "CLEAVE" }, MartialTrees.Berserker, "Equip a pair of dual-wielded axes to unlock.", "AxeEarly"), new ClassDefinition("highlander", "Highlander", "Fight with two-handed swords, and carry a single axe or pickaxe to gather. An executioner: wait for the swing, mark what is dying, and finish it outright.", new string[6] { "EXECUTION", "HEFT", "MORTAL", "BREAK", "RESOLVE", "HEADSMAN" }, MartialTrees.Highlander, "Equip a two-handed sword to unlock.", "THSwordKrom"), new ClassDefinition("breaker", "Breaker", "Fight with two-handed axes, and carry a pickaxe to mine. A breaker: crack an enemy open blow by blow, then spend the damage the moment it loses its footing.", new string[6] { "FRACTURE", "SHATTER", "QUAKE", "ANVIL", "ENDURE", "SUNDER" }, MartialTrees.Breaker, "Equip a two-handed axe to unlock.", "Battleaxe"), new ClassDefinition("dragonsworn", "Dragonsworn", "Fight alongside a young dragon of Moder's brood. It climbs while you wait and you spend the height on one stoop. No metal armour.", new string[6] { "SCALES", "RIME", "ALTITUDE", "STOOP", "BROOD", "KINSHIP" }, DragonTree.Talents, "Carry a dragon tear to unlock.", "TrophyDragonQueen") }); public static ClassDefinition? Find(string id) { return All.FirstOrDefault((ClassDefinition c) => c.Id == id); } } public static class ClassResources { public static float Health(Progression state) { return state.Definition?.Talents.Where((Talent t) => state.Has(t.Id)).Sum((Talent t) => t.MaximumHealth) ?? 0f; } public static float Stamina(Progression state) { return state.Definition?.Talents.Where((Talent t) => state.Has(t.Id)).Sum((Talent t) => t.MaximumStamina) ?? 0f; } } public static class DefenseTree { public const int NodeCount = 4; public static string Id(string classId, int rank) { return classId + "_defense_" + rank; } public static int Rank(Progression state) { for (int num = 4; num > 0; num--) { if (state.Has(Id(state.ClassId, num))) { return num; } } return 0; } public static IReadOnlyList<Talent> Append(string classId, IReadOnlyList<Talent> original, int branch) { List<Talent> list = original.ToList(); string prerequisite = original.Single((Talent t) => t.Prerequisite == null).Id; for (int num = 1; num <= 4; num++) { (string, string, string) tuple = Describe(classId, num); string text = Id(classId, num); list.Add(new Talent(text, tuple.Item1, tuple.Item2, prerequisite, tuple.Item3, branch, num, 0f, 0f, num == 4)); prerequisite = text; } return list.AsReadOnly(); } public static float EitrEfficiency(int rank) { if (rank != 0) { return 1f + (float)(rank - 1) * 0.25f; } return 0f; } public static float PoolFraction(int rank, int level) { return (float)Math.Max(0, Math.Min(4, rank)) * 0.05f * (0.5f + 0.5f * (float)(Math.Max(1, Math.Min(80, level)) - 1) / 79f); } public static float Capacity(Progression state, float maxHealth) { if (!float.IsNaN(maxHealth) && !float.IsInfinity(maxHealth)) { return Math.Max(0f, maxHealth) * PoolFraction(Rank(state), state.Level); } return 0f; } public static float WolfShare(int rank) { if (rank != 0) { return 0.15f + (float)rank * 0.05f; } return 0f; } public static float CompanionRange(int rank) { return (rank != 0) ? (8 + rank * 4) : 0; } public static float Reduction(int rank) { return (float)rank * 0.05f; } public static string Description(Progression state, Talent talent) { return Description(state.ClassId, state.Level, talent); } public static string Description(string classId, int level, Talent talent) { if (talent.Branch != 6 || !talent.Id.StartsWith(classId + "_defense_", StringComparison.Ordinal)) { return talent.Description; } return Describe(classId, talent.Tier, level).description; } private static (string name, string description, string icon) Describe(string id, int rank, int level = 80) { string text = ((rank == 1) ? "" : (" " + (new string[5] { "", "", "II", "III", "IV" })[rank])); float num = Reduction(rank) * 100f; string text2 = $"{PoolFraction(rank, level) * 100f:0.##}% max HP"; string text3; string item; string item2; switch (id) { case "mage": text3 = "Eitr Shield"; item = "Eitr"; item2 = $"Damage spends Eitr before health, after armour: 1 Eitr absorbs {EitrEfficiency(rank):0.##} damage. Excess reaches health. Spells use the same reserve."; break; case "warlock": text3 = "Self-Ward"; item = "StaffShield"; item2 = "Ward: " + text2 + ", scaling with class level. Reforms after 12s without damage; starts empty. Excess hurts. Blood costs bypass it."; break; case "hunter": text3 = "Shared Burden"; item = "TrophyWolf"; item2 = $"Your living bonded wolf within {CompanionRange(rank):0}m takes {WolfShare(rank) * 100f:0}% of damage after your armour. The share bypasses wolf armour and can kill it. No wolf means full damage."; break; case "huscarl": text3 = "Weapon Guard"; item = "SwordIron"; item2 = $"Weapon blocks bank half the damage stopped, up to {text2}, for 6s. Cap scales with class level. Blocking also takes {num:0}% less damage."; break; case "shieldbearer": text3 = "Living Bulwark"; item = "ShieldBanded"; item2 = $"Block wards you and 2 allies within 8m for {text2} each, 6s, every 8s. Scales with your level. Shield: {num:0}% less damage, doubled blocking."; break; case "valkyrie": text3 = "Sky Mantle"; item = "CapeFeather"; item2 = $"After 1s airborne, gain {text2} guard until 4s after landing. Every 10s; scales with class level. Air/fall damage reduced {num:0}%."; break; case "ranger": text3 = "Evasive Stride"; item = "CapeDeerHide"; item2 = $"Walk 6m to guard the next hit for {text2}, scaling with class level. One charge. Dodging also reduces damage {num:0}% for 4s."; break; case "rogue": text3 = "Fade Away"; item = "KnifeFlint"; item2 = $"Dodge guards the next hit for {text2} within 2s, every 8s. Scales with class level. Dodging also reduces damage {num * 2f:0}% for 2s."; break; case "monk": text3 = "Flow Guard"; item = "FistFenrirClaw"; item2 = "Fist/claw hits guard the next hit for " + text2 + " within 3s, every 4s. Scales with class level. Requires fists/claws; spends no stamina."; break; case "berserker": text3 = "Blood Hide"; item = "AxeEarly"; item2 = $"Paired-axe hits bank 20% of damage, up to {text2}, for 5s. Cap scales with class level. At half health, take {num * 2f:0}% less damage."; break; case "highlander": text3 = "Iron Commitment"; item = "THSwordKrom"; item2 = $"Stand still 1.5s with a greatsword: guard one hit during your next swing for {text2}, scaling with class level. Attacks take {num * 2f:0}% less damage."; break; case "breaker": text3 = "Anvil Guard"; item = "Battleaxe"; item2 = $"Wielding a battleaxe:\nAlways take {num:0}% less damage ({num * 2f:0}% while you are staggered).\nDamaging hits leaving foes staggered grant or refresh {rank + 2}s stagger immunity."; break; case "dragonsworn": text3 = "Brood Shelter"; item = "TrophyDragonQueen"; item2 = $"Whelp within {CompanionRange(rank):0}m: {num:0}% less damage. Spend 25% altitude to absorb {text2}, every 3s. Absorption scales with class level."; break; default: throw new ArgumentException("Defense branch missing for " + id); } return (name: text3 + ((rank == 4) ? "" : text), description: item2, icon: item); } } public readonly struct DefenseContext { public readonly bool Blocking; public readonly bool Shield; public readonly bool Airborne; public readonly bool Attacking; public readonly bool Staggering; public readonly bool WeaponReady; public readonly bool CompanionNear; public readonly float HealthFraction; public readonly float Eitr; public readonly float Stamina; public readonly float Altitude; public DefenseContext(float healthFraction = 1f, float eitr = 0f, float stamina = 0f, bool blocking = false, bool shield = false, bool airborne = false, bool attacking = false, bool staggering = false, bool weaponReady = true, bool companionNear = false, float altitude = 0f) { HealthFraction = healthFraction; Eitr = eitr; Stamina = stamina; Altitude = altitude; Blocking = blocking; Shield = shield; Airborne = airborne; Attacking = attacking; Staggering = staggering; WeaponReady = weaponReady; CompanionNear = companionNear; } } public readonly struct DefenseResult { public readonly float Damage; public readonly float EitrSpent; public readonly float StaminaSpent; public readonly float Shared; public readonly float AltitudeSpent; public DefenseResult(float damage, float eitr = 0f, float stamina = 0f, float shared = 0f, float altitude = 0f) { Damage = damage; EitrSpent = eitr; StaminaSpent = stamina; Shared = shared; AltitudeSpent = altitude; } } public sealed class DefenseCombat { private float _maxHealth; private string _class = ""; private int _rank; private float _ward; private float _wardReadyAt; private float _dodgeUntil; private float _guard; private float _guardUntil; private float _travel; private float _airSince = -1f; private float _steadySince = -1f; private float _nextCover; private float _nextAfterimage; private float _nextWings; private float _nextStrike; private float _nextIntercept; private float _anchorUntil; private bool _airborne; private bool _wingCharged; private bool _swinging; public float WardRemaining => _ward; public float GuardRemaining => _guard; public float TravelProgress => _travel; public DefenseCombat(float maxHealth = 0f) { SetMaximumHealth(maxHealth); } public void SetMaximumHealth(float maxHealth) { float num = ((float.IsNaN(maxHealth) || float.IsInfinity(maxHealth)) ? 0f : Math.Max(0f, maxHealth)); if (num != _maxHealth) { float num2 = ((_maxHealth > 0f) ? (num / _maxHealth) : 0f); _ward *= num2; _guard *= num2; _maxHealth = num; } } public float WardDelay(float now) { if (!(_class == "warlock") || _rank <= 0) { return 0f; } return Math.Max(0f, _wardReadyAt - now); } public void Clear() { _class = ""; _rank = 0; _ward = 0f; _wardReadyAt = 0f; _dodgeUntil = 0f; _guard = 0f; _guardUntil = 0f; _travel = 0f; _airSince = -1f; _steadySince = -1f; _nextCover = (_nextAfterimage = (_nextWings = (_nextStrike = (_nextIntercept = (_anchorUntil = 0f))))); _airborne = (_wingCharged = (_swinging = false)); } public void Tick(Progression state, float now) { int num = DefenseTree.Rank(state); if (_class != state.ClassId || _rank != num) { float ward = ((_class == "warlock" && state.ClassId == "warlock" && _rank > 0 && num > 0) ? Math.Min(_ward, DefenseTree.Capacity(state, _maxHealth)) : 0f); Clear(); _ward = ward; _wardReadyAt = now + 12f; _class = state.ClassId; _rank = num; } if (_class == "warlock" && _rank > 0 && now >= _wardReadyAt) { _ward = DefenseTree.Capacity(state, _maxHealth); } _guard = Math.Min(_guard, DefenseTree.Capacity(state, _maxHealth)); _ward = Math.Min(_ward, DefenseTree.Capacity(state, _maxHealth)); if (now >= _guardUntil) { _guard = 0f; } } public void Dodge(Progression state, float now) { Tick(state, now); _dodgeUntil = now + (float)((state.ClassId == "ranger") ? 4 : ((state.ClassId == "rogue") ? 2 : 0)); if (_class == "rogue" && _rank > 0 && now >= _nextAfterimage) { _guard = DefenseTree.Capacity(state, _maxHealth); _guardUntil = now + 2f; _nextAfterimage = now + 8f; } } public float Block(Progression state, float now, float stopped, bool weaponReady, bool shield) { Tick(state, now); if (_rank == 0 || stopped <= 0f || float.IsNaN(stopped) || float.IsInfinity(stopped)) { return 0f; } if (_class == "huscarl" && weaponReady) { _guard = Math.Min(DefenseTree.Capacity(state, _maxHealth), _guard + stopped * 0.5f); _guardUntil = now + 6f; } if (_class == "shieldbearer" && shield && now >= _nextCover) { _nextCover = now + 8f; return DefenseTree.PoolFraction(_rank, state.Level); } return 0f; } public void Travel(Progression state, float now, float metres) { Tick(state, now); if (!(_class != "ranger") && _rank != 0 && !(_guard > 0f) && !(metres <= 0f) && !(metres > 2f) && !float.IsNaN(metres)) { _travel += metres; if (_travel >= 6f) { _travel = 0f; _guard = DefenseTree.Capacity(state, _maxHealth); _guardUntil = float.PositiveInfinity; } } } public void Air(Progression state, float now, bool airborne) { Tick(state, now); if (!(_class != "valkyrie") && _rank != 0) { if (airborne && !_airborne) { _airSince = now; _wingCharged = false; } if (airborne && !_wingCharged && _airSince >= 0f && now - _airSince >= 1f && now >= _nextWings) { _guard = DefenseTree.Capacity(state, _maxHealth); _guardUntil = float.PositiveInfinity; _nextWings = now + 10f; _wingCharged = true; } if (!airborne && _airborne && _guard > 0f) { _guardUntil = now + 4f; } _airborne = airborne; } } public void Posture(Progression state, float now, bool still, bool attacking, bool weaponReady) { Tick(state, now); if (_class != "highlander" || _rank == 0) { return; } if (_swinging && !attacking) { _guard = 0f; } _swinging = attacking; if (!weaponReady || (!attacking && !still)) { _guard = 0f; _steadySince = -1f; return; } if (attacking) { _steadySince = -1f; return; } if (_steadySince < 0f) { _steadySince = now; } if (now - _steadySince >= 1.5f) { _guard = DefenseTree.Capacity(state, _maxHealth); _guardUntil = float.PositiveInfinity; } } public void Strike(Progression state, float now, float healthLost, bool enemyStaggered, bool weaponReady) { Tick(state, now); if (_rank != 0 && weaponReady && !(healthLost <= 0f) && !float.IsNaN(healthLost) && !float.IsInfinity(healthLost) && !(now < _nextStrike)) { if (_class == "monk") { _guard = DefenseTree.Capacity(state, _maxHealth); _guardUntil = now + 3f; _nextStrike = now + 4f; } if (_class == "berserker") { _guard = Math.Min(DefenseTree.Capacity(state, _maxHealth), _guard + healthLost * 0.2f); _guardUntil = now + 5f; _nextStrike = now + 0.5f; } if (_class == "breaker" && enemyStaggered) { _anchorUntil = now + (float)_rank + 2f; _nextStrike = now + 0.5f; } } } public bool PreventStagger(Progression state, float now, bool weaponReady) { Tick(state, now); if (_class == "breaker" && _rank > 0 && weaponReady) { return now < _anchorUntil; } return false; } public string Status(Progression state, float now) { Tick(state, now); if (_rank == 0) { return ""; } switch (_class) { case "huscarl": return $"Weapon guard: {_guard:0}"; case "shieldbearer": if (!(now < _nextCover)) { return "Shelter: block to ward allies"; } return $"Shelter: {_nextCover - now:0.0}s"; case "valkyrie": return $"Sky mantle: {_guard:0}"; case "ranger": if (!(_guard > 0f)) { return $"Trail cover: {_travel:0.0}/6m"; } return $"Trail cover: {_guard:0}"; case "rogue": if (!(_guard > 0f)) { if (!(now < _nextAfterimage)) { return "Afterimage: ready on dodge"; } return $"Afterimage: {_nextAfterimage - now:0.0}s"; } return $"Afterimage: {_guard:0}"; case "monk": if (!(_guard > 0f)) { if (!(now < _nextStrike)) { return "Flow guard: land a fist/claw hit"; } return $"Flow guard: {_nextStrike - now:0.0}s"; } return $"Flow guard: {_guard:0}"; case "berserker": return $"Blood hide: {_guard:0}"; case "highlander": return $"Iron poise: {_guard:0}"; case "breaker": if (!(now < _anchorUntil)) { return "Unshakable: break an enemy"; } return $"Unshakable: {_anchorUntil - now:0.0}s"; case "dragonsworn": if (!(now < _nextIntercept)) { return "Wing intercept: spends 25% altitude"; } return $"Wing intercept: {_nextIntercept - now:0.0}s"; default: return ""; } } public DefenseResult Resolve(Progression state, float now, float damage, DefenseContext context) { Tick(state, now); if (damage <= 0f || float.IsNaN(damage) || float.IsInfinity(damage) || _rank == 0) { return new DefenseResult(damage); } float num = DefenseTree.Reduction(_rank); switch (state.ClassId) { case "mage": { float num3 = Math.Min(damage, Math.Max(0f, context.Eitr) * DefenseTree.EitrEfficiency(_rank)); return new DefenseResult(damage - num3, num3 / DefenseTree.EitrEfficiency(_rank)); } case "warlock": { float num4 = Math.Min(damage, _ward); _ward -= num4; _wardReadyAt = now + 12f; return new DefenseResult(damage - num4); } case "hunter": { float num2 = (context.CompanionNear ? (damage * DefenseTree.WolfShare(_rank)) : 0f); return new DefenseResult(damage - num2, 0f, 0f, num2); } case "monk": num = 0f; break; case "huscarl": num = ((context.Blocking && context.WeaponReady) ? num : 0f); break; case "shieldbearer": num = (context.Shield ? (num * (float)((!context.Blocking) ? 1 : 2)) : 0f); break; case "valkyrie": num = (context.Airborne ? num : 0f); break; case "ranger": num = ((now < _dodgeUntil) ? num : 0f); break; case "rogue": num = ((now < _dodgeUntil) ? (num * 2f) : 0f); break; case "berserker": num = ((context.WeaponReady && context.HealthFraction <= 0.5f) ? (num * 2f) : 0f); break; case "highlander": num = ((context.WeaponReady && context.Attacking) ? (num * 2f) : 0f); break; case "breaker": num = (context.WeaponReady ? (num * (float)((!context.Staggering) ? 1 : 2)) : 0f); break; case "dragonsworn": num = (context.CompanionNear ? num : 0f); break; default: num = 0f; break; } float num5 = damage * (1f - num); float altitude = 0f; bool num6; if (!(state.ClassId == "huscarl")) { if (!(state.ClassId == "highlander")) { if (!(state.ClassId == "berserker") && !(state.ClassId == "monk")) { goto IL_0488; } num6 = context.WeaponReady; } else { if (!context.WeaponReady) { goto IL_050a; } num6 = context.Attacking; } } else { num6 = context.WeaponReady; } if (num6) { goto IL_0488; } goto IL_050a; IL_0488: if (_guard > 0f) { float num7 = Math.Min(num5, _guard); num5 -= num7; _guard -= num7; if (state.ClassId == "rogue" || state.ClassId == "ranger" || state.ClassId == "highlander" || state.ClassId == "monk") { _guard = 0f; } } goto IL_050a; IL_050a: if (state.ClassId == "highlander") { _steadySince = -1f; } if (state.ClassId == "dragonsworn" && context.CompanionNear && context.Altitude >= 0.25f && now >= _nextIntercept) { num5 = Math.Max(0f, num5 - DefenseTree.Capacity(state, _maxHealth)); altitude = 0.25f; _nextIntercept = now + 3f; } return new DefenseResult(num5, 0f, 0f, 0f, altitude); } } public static class DragonTree { private static readonly TreeWeb.Node[] Trunk = new TreeWeb.Node[25] { new TreeWeb.Node("dg_bond", "Sworn to the Brood", "Your whelp's maximum health is 10% higher. Use the companion key to call it, or to send it into a stoop at the enemy you are looking at.", "TrophyDragonQueen", Bonus.PetHealth, 10f), new TreeWeb.Node("dg_scale", "Rimed Scales", "Your whelp's maximum health is another 10% higher.", "ScaleHide", Bonus.PetHealth, 10f), new TreeWeb.Node("dg_plate", "Plated Hide", "Your whelp takes 10% less damage.", "ArmorCarapaceChest"), new TreeWeb.Node("dg_gorge", "Gorged", "Your whelp's maximum health is another 10% higher.", "RawMeat", Bonus.PetHealth, 10f), new TreeWeb.Node("dg_hide", "Dragonhide", "Your whelp's maximum health is another 15% higher.", "ScaleHide", Bonus.PetHealth, 15f), new TreeWeb.Node("dg_frost", "Frostbite", "Your whelp deals 10% more damage.", "FreezeGland", Bonus.PetDamage, 10f), new TreeWeb.Node("dg_bite", "Rime-Edged Teeth", "Your whelp deals another 10% more damage.", "TrophyHatchling", Bonus.PetDamage, 10f), new TreeWeb.Node("dg_creep", "Creeping Cold", "You take 10% less frost damage.", "HelmetDrake", Bonus.Frost, 0.1f), new TreeWeb.Node("dg_hoar", "Hoarfrost", "A damaging strike from your whelp rimes its target for 8 seconds: it moves 20% slower and your own hits on it deal 10% more damage. Once every 8 seconds.", "FreezeGland"), new TreeWeb.Node("dg_thermal", "Thermals", "Your whelp reaches its ceiling in 22 seconds instead of 26.", "Feathers"), new TreeWeb.Node("dg_ceiling", "High Ceiling", "A stoop from the full ceiling is worth 60% more damage instead of 50%.", "DragonTear"), new TreeWeb.Node("dg_glide", "Long Glide", "A stoop reaches 26 metres instead of 20.", "CapeFeather"), new TreeWeb.Node("dg_shadow", "Shadow of the Wing", "While your whelp is holding its ceiling, your bow and crossbow hits deal 8% more damage.", "BowDraugrFang"), new TreeWeb.Node("dg_dive", "Sure Dive", "Your whelp deals another 10% more damage.", "TrophyHatchling", Bonus.PetDamage, 10f), new TreeWeb.Node("dg_talon", "Talons", "Your whelp's strikes cause 5% more stagger.", "TrophyDragonQueen", Bonus.PetStagger, 5f), new TreeWeb.Node("dg_mark", "Spotted", "After your whelp damages an enemy, your weapon hits against that enemy deal 12% more damage for 6 seconds. Only its most recent target is marked.", "ArrowObsidian"), new TreeWeb.Node("dg_down", "Downdraft", "A stoop's arrival shoves every enemy within 5 metres of your whelp away from it. Large enemies resist through their normal mass.", "Feathers"), new TreeWeb.Node("dg_rest", "Restful Wing", "Your whelp regenerates its health in 20 minutes instead of 60, while native regeneration is allowed.", "RawMeat"), new TreeWeb.Node("dg_feed", "Fed on Tears", "Your whelp's maximum health is another 10% higher.", "DragonTear", Bonus.PetHealth, 10f), new TreeWeb.Node("dg_breathe", "Warm Breath", "Gain 5 maximum stamina while this class is active. Adds to food bonuses; does not refill stamina.", "MeadStaminaMinor", Bonus.MaximumStamina, 5f), new TreeWeb.Node("dg_warm", "Warm the Scales", "Crouch and press the companion key to heal your nearby whelp for 60% of its maximum health. Once every 35 seconds; requires clear sight within 10 metres.", "MeadHealthMedium"), new TreeWeb.Node("dg_kin_warm", "Shared Warmth", "Normal health regeneration is 5% faster.", "MeadHealthMinor", Bonus.Health, 0.05f), new TreeWeb.Node("dg_kin_heart", "Wyrm's Heart", "Gain 5 maximum health while this class is active. Adds to food bonuses; does not refill health.", "MeadHealthMinor", Bonus.MaximumHealth, 5f), new TreeWeb.Node("dg_kin_wind", "Cold Lungs", "Stamina regenerates 4% faster while it can normally regenerate.", "MeadStaminaMedium", Bonus.Regen, 0.04f), new TreeWeb.Node("dg_kin_bond", "Bound Blood", "When your whelp's strike damages an enemy you recover 3 health and 5 stamina. Once every 12 seconds; requires you within 40 metres.", "MeadHealthMedium") }; private static readonly TreeWeb.Lane[] Lanes = new TreeWeb.Lane[12] { new TreeWeb.Lane("dg_hide", "Ironscale", new TreeWeb.Node("dg_iron_bulk", "Bulk", "Your whelp's maximum health is another 10% higher.", "ScaleHide", Bonus.PetHealth, 10f), new TreeWeb.Node("dg_iron_cold", "Coldproof", "Plated Hide is worth 20% instead of 10%.", "ArmorCarapaceChest"), new TreeWeb.Node("dg_iron_poise", "Unshaken", "Your whelp's strikes cause another 5% more stagger.", "TrophyDragonQueen", Bonus.PetStagger, 5f), new TreeWeb.Node("dg_iron_last", "Broodmother's Refusal", "A blow that would kill your whelp leaves it at half health instead. Once every 5 minutes.", "TrophyDragonQueen")), new TreeWeb.Lane("dg_hide", "Warden", new TreeWeb.Node("dg_ward_heart", "Warden's Heart", "Gain 5 maximum health while this class is active. Adds to food bonuses; does not refill health.", "MeadHealthMinor", Bonus.MaximumHealth, 5f), new TreeWeb.Node("dg_ward_poise", "Braced", "Take 5% less stagger buildup.", "HelmetDrake", Bonus.Stagger, 0.05f), new TreeWeb.Node("dg_ward_frost", "Cold Blood", "You take another 15% less frost damage.", "ArmorWolfChest", Bonus.Frost, 0.15f), new TreeWeb.Node("dg_ward_warm", "Warm Blood", "While your whelp is alive within 40 metres you cannot freeze: the freezing the mountains and the deep north apply is lifted as it lands.", "MeadFrostResist")), new TreeWeb.Lane("dg_hoar", "Deepfreeze", new TreeWeb.Node("dg_rime_deep", "Deep Rime", "A rimed enemy takes 18% more damage from your hits instead of 10%.", "FreezeGland"), new TreeWeb.Node("dg_rime_long", "Long Rime", "The rime holds 12 seconds instead of 8.", "Crystal"), new TreeWeb.Node("dg_rime_quick", "Quick Rime", "Hoarfrost's cooldown falls from 8 to 5 seconds.", "FreezeGland"), new TreeWeb.Node("dg_rime_slow", "Leaden Cold", "A rimed enemy moves 35% slower instead of 20%.", "Crystal"), new TreeWeb.Node("dg_rime_shatter", "Shatter", "Your hit on a rimed enemy at or below a third of its health deals 40% more damage and ends the rime.", "MaceSilver")), new TreeWeb.Lane("dg_hoar", "Spread", new TreeWeb.Node("dg_spread_cone", "Frost Breath", "The breath that ends a stoop catches every other enemy in a 45-degree cone 6 metres from your whelp, for 35% of its damage.", "StaffIceShards"), new TreeWeb.Node("dg_spread_reach", "Deep Lungs", "The breath reaches 9 metres instead of 6.", "StaffIceShards"), new TreeWeb.Node("dg_spread_wide", "Wide Maw", "The breath opens to 70 degrees instead of 45.", "TrophyDragonQueen"), new TreeWeb.Node("dg_spread_share", "Full Throat", "The breath is worth 55% of the strike instead of 35%.", "FreezeGland"), new TreeWeb.Node("dg_spread_rime", "Whiteout", "Everything the breath catches is rimed, ignoring Hoarfrost's own cooldown.", "Crystal")), new TreeWeb.Lane("dg_shadow", "Updraft", new TreeWeb.Node("dg_up_fast", "Rising Air", "Your whelp reaches its ceiling in 18 seconds instead of 22.", "Feathers"), new TreeWeb.Node("dg_up_half", "Half Measure", "A stoop may be spent from half the ceiling, and is worth the height it actually spends.", "CapeFeather"), new TreeWeb.Node("dg_up_keep", "Kept Wing", "A stoop spends three quarters of the height it had rather than all of it.", "Feathers"), new TreeWeb.Node("dg_up_dive", "Terminal Velocity", "A stoop from the full ceiling is worth 100% more damage instead of 60%.", "DragonTear")), new TreeWeb.Lane("dg_shadow", "Overwatch", new TreeWeb.Node("dg_over_eye", "Spotter", "Bow and crossbow attacks cost 5% less stamina.", "BowHuntsman", Bonus.AttackCost, 0.05f), new TreeWeb.Node("dg_over_mark", "Higher Still", "Shadow of the Wing is worth 15% instead of 8%.", "BowDraugrFang"), new TreeWeb.Node("dg_over_fall", "Lightfall", "While your whelp is holding its ceiling you take no fall damage.", "CapeFeather"), new TreeWeb.Node("dg_over_calm", "Eye of the Storm", "While your whelp is holding its ceiling your stamina regenerates 25% faster.", "MeadStaminaMedium")), new TreeWeb.Lane("dg_down", "Gale", new TreeWeb.Node("dg_gale_force", "Full Gale", "The downdraft is half again as strong.", "Feathers"), new TreeWeb.Node("dg_gale_wide", "Broad Gale", "The downdraft reaches 8 metres instead of 5.", "TrophyDragonQueen"), new TreeWeb.Node("dg_gale_rime", "Bitter Wind", "Everything the downdraft shoves is rimed.", "FreezeGland"), new TreeWeb.Node("dg_gale_stagger", "Grounded", "The downdraft staggers everything it shoves outright.", "MaceSilver")), new TreeWeb.Lane("dg_down", "Wake", new TreeWeb.Node("dg_chase_run", "Long Stride", "Running costs 8% less stamina.", "CapeDeerHide", Bonus.Run, 0.08f), new TreeWeb.Node("dg_chase_dodge", "Duck Aside", "Dodging costs 5% less stamina.", "ArmorLeatherLegs", Bonus.Dodge, 0.05f), new TreeWeb.Node("dg_chase_jump", "Kick Off", "Jumping costs 10% less stamina.", "Feathers", Bonus.Jump, 0.1f), new TreeWeb.Node("dg_chase_free", "Follow It Down", "For 6 seconds after a stoop your running and dodging cost no stamina.", "CapeFeather")), new TreeWeb.Lane("dg_warm", "Hearth", new TreeWeb.Node("dg_hearth_full", "Full Warmth", "Warm the Scales restores all of the whelp's health instead of 60%.", "MeadHealthMedium"), new TreeWeb.Node("dg_hearth_quick", "Quick Warmth", "Warm the Scales' cooldown falls from 35 to 22 seconds.", "MeadHealthMinor"), new TreeWeb.Node("dg_hearth_far", "Long Arm", "Warm the Scales reaches 20 metres instead of 10.", "RawMeat"), new TreeWeb.Node("dg_hearth_ward", "Tempered Scales", "A whelp you have just warmed takes 50% less damage for 8 seconds.", "ArmorCarapaceChest")), new TreeWeb.Lane("dg_warm", "Nest", new TreeWeb.Node("dg_nest_rest", "Deep Sleep", "Your whelp regenerates its health in 8 minutes instead of 20, while native regeneration is allowed.", "RawMeat"), new TreeWeb.Node("dg_nest_hide", "Thick Scale", "Your whelp's maximum health is another 10% higher.", "ScaleHide", Bonus.PetHealth, 10f), new TreeWeb.Node("dg_nest_climb", "Nested Wing", "A whelp you have just warmed is at its ceiling at once.", "Feathers"), new TreeWeb.Node("dg_nest_call", "Second Clutch", "A fallen whelp can be called back after 90 seconds instead of three minutes.", "TrophyDragonQueen")), new TreeWeb.Lane("dg_kin_bond", "Tithe", new TreeWeb.Node("dg_tithe_deep", "Deep Tithe", "Bound Blood pays 6 health and 10 stamina instead of 3 and 5.", "MeadHealthMedium"), new TreeWeb.Node("dg_tithe_quick", "Quick Tithe", "Bound Blood's cooldown falls from 12 to 8 seconds.", "MeadStaminaMinor"), new TreeWeb.Node("dg_tithe_far", "Distant Bond", "Every strike-triggered benefit reaches 70 metres instead of 40.", "TrophyDragonQueen"), new TreeWeb.Node("dg_tithe_dive", "Blood of the Brood", "The breath that ends a stoop heals you for a tenth of the damage it deals.", "MeadHealthMedium")), new TreeWeb.Lane("dg_kin_bond", "Dread", new TreeWeb.Node("dg_dread_stam", "Long Wind", "G
BepInEx/plugins/WarriorRpg/WarriorRpg.dll
Decompiled 2 hours 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.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using SoftReferenceableAssets; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; using Valheim.SettingsGui; using Warrior.Core; [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("WarriorRpg")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.21.7.0")] [assembly: AssemblyInformationalVersion("0.21.7+75524a93b33122b85192c86102f300b04ef67a8e")] [assembly: AssemblyProduct("WarriorRpg")] [assembly: AssemblyTitle("WarriorRpg")] [assembly: AssemblyVersion("0.21.7.0")] [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 Warrior.Mod { [BepInPlugin("local.warrior.rpg", "Oathbound", "0.21.7")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal enum VfxKind { Warcry, WarcryStrike, StandFast, StandFastAlly, Vanish, Focus, Whirl, WhirlStrike, PierceLaunch, PierceStrike, PierceFlight, SpearConjure, SpearStrike, SpearFlight, HandSpear, HandSpearGone, HunterCall, HunterMend, Sunder, SunderStrike, DragonCall, DragonWarm, DragonBreath, DragonGale, DefenseReady, DefenseHit, DefenseBreak } private sealed class Vfx { private readonly EffectList _list; private readonly float _scale; internal bool Ready => Resolved(_list); internal Vfx(float scale, params string[] names) { _scale = scale; _list = EffectListOf(scale, names); } internal void Play(Vector3 position, Quaternion rotation, Player? owner = null) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) _list.Create(position, rotation, (Transform)null, _scale, -1, ((Object)(object)owner != (Object)null) ? ((Character)owner).GetZDOID() : ZDOID.None); } } private sealed class AbilityGlow : MonoBehaviour { private Light _light; private float _until; private float _peak; private float _fade; internal void Configure(float seconds, float range, float intensity, Color color, float fade) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) _light = ((Component)this).gameObject.AddComponent<Light>(); _light.type = (LightType)2; _light.color = color; _light.range = range; _light.shadows = (LightShadows)0; _light.intensity = intensity; _peak = intensity; _fade = Mathf.Clamp((fade > 0f) ? fade : (seconds * 0.5f), 0.05f, Mathf.Max(0.05f, seconds)); _until = Time.unscaledTime + seconds; } private void Update() { if ((Object)(object)_light == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } float num = _until - Time.unscaledTime; if (num <= 0f) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { _light.intensity = _peak * Mathf.Clamp01(num / _fade); } } } private struct VfxBeat { internal VfxKind Kind; internal Vector3 Position; internal Vector3 Forward; internal ZDOID Owner; internal ZDOID Target; internal string Item; internal float Amount; internal float Deadline; } private sealed class VfxSpend { internal float Window; internal int Count; } [HarmonyPatch(typeof(Player), "Load")] private static class EquipmentLoadPatch { private static void Prefix(Player __instance) { LoadingEquipment.Add(__instance); } private static void Finalizer(Player __instance) { LoadingEquipment.Remove(__instance); } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class BerserkerBloodPatch { private static void Prefix(Character __instance, out float __state) { __state = __instance.GetHealth(); } private static void Postfix(Character __instance, HitData hit, float __state) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_0064: Unknown result type (might be due to invalid IL or missing references) Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (!((Object)(object)val == (Object)null) && ((Component)__instance).GetComponent<ZNetView>().IsOwner() && !hit.m_ranged && (int)hit.m_skill == 7 && !(__state <= Mathf.Max(0f, __instance.GetHealth())) && EnemyHit((Character)(object)val, __instance)) { ((Component)val).GetComponent<ZNetView>().InvokeRPC("Oathbound_BerserkerHit_1", new object[1] { __instance.GetZDOID() }); } } } [HarmonyPatch(typeof(Character), "Awake")] private static class BerserkerRpcPatch { private static void Postfix(Character __instance) { Player player = (Player)(object)((__instance is Player) ? __instance : null); if (player == null) { return; } ZNetView view = ((Component)player).GetComponent<ZNetView>(); if ((Object)(object)view == (Object)null || !view.IsValid()) { return; } view.Register<ZDOID>("Oathbound_BerserkerHit_1", (Action<long, ZDOID>)delegate(long sender, ZDOID id) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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) Progression val = MartialState((Character)(object)player); GameObject obj = ZNetScene.instance.FindInstance(id); Character val2 = ((obj != null) ? obj.GetComponent<Character>() : null); if (view.IsOwner() && !(((val != null) ? val.ClassId : null) != "berserker") && !((Object)(object)val2 == (Object)null) && ((Component)val2).GetComponent<ZNetView>().GetZDO().GetOwner() == sender && EnemyHit((Character)(object)player, val2) && !(Vector3.Distance(((Component)player).transform.position, ((Component)val2).transform.position) > 12f)) { float num = Instance._martial.OnBloodHit(val, (double)Time.unscaledTime, ((Character)player).GetHealthPercentage()); if (num > 0f) { ((Character)player).Heal(num, false); } } }); } } [HarmonyPatch(typeof(BaseAI), "CanSeeTarget", new Type[] { typeof(Transform), typeof(Vector3), typeof(float), typeof(float), typeof(bool), typeof(bool), typeof(Character) })] private static class BloodMoonSight { private static void Prefix(ref float viewRange, ref float viewAngle, Character target) { float num = (((Object)(object)Instance != (Object)null && Instance._bloodMoonActive && (Object)(object)target != (Object)null && target.IsPlayer()) ? Instance._bloodMoonSenseNow : 1f); if (!(num <= 1f)) { viewRange *= num; viewAngle = Mathf.Min(180f, viewAngle * num); } } } [HarmonyPatch(typeof(Character), "GetNoiseRange")] private static class BloodMoonNoise { private static void Postfix(Character __instance, ref float __result) { if (!((Object)(object)Instance == (Object)null) && Instance._bloodMoonActive && !(__result <= 0f) && __instance.IsPlayer()) { __result *= Instance._bloodMoonSenseNow; } } } [HarmonyPatch(typeof(SpawnSystem), "GetLevelUpChance", new Type[] { typeof(Vector3), typeof(float) })] private static class BloodMoonStars { private static void Postfix(ref float __result) { if (!((Object)(object)Instance == (Object)null) && Instance._bloodMoonActive && !(__result <= 0f)) { __result = Mathf.Min(100f, __result * Instance._bloodMoonStarNow); } } } [HarmonyPatch(typeof(Bed), "CheckEnemies")] private static class BloodMoonSleep { private static bool Prefix(Player human, ref bool __result) { if (!BloodMoonSleepLocked()) { return true; } __result = false; if ((Object)(object)human != (Object)null) { ((Character)human).Message((MessageType)2, "You cannot sleep while the blood moon is still rising.", 0, (Sprite)null, false); } return false; } } private sealed class Bleed { internal Character Target; internal string ClassId = ""; internal string Talent = ""; internal float TickDamage; internal float NextTick; internal int Remaining = 3; internal bool Fire; } [HarmonyPatch(typeof(Character), "Jump")] private static class AirStepPatch { private static void Prefix(Character __instance, out bool __state) { __state = (Object)(object)__instance == (Object)(object)Player.m_localPlayer && !__instance.IsOnGround() && !__instance.IsSwimming() && !__instance.IsDead() && !__instance.IsEncumbered() && !__instance.InDodge() && !__instance.InAttack() && !__instance.IsKnockedBack() && !__instance.IsStaggering() && !__instance.IsTeleporting() && !__instance.InCutscene() && !BlocksInput && !Object.op_Implicit((Object)(object)GrapplingPoint.m_localGrappler); } private static void Postfix(Character __instance, bool __state) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) Progression val = (__state ? ActiveState(__instance, "valkyrie") : null); if (val != null && Instance._vikings.TryAirStep(val)) { Vector3 linearVelocity = ((Component)__instance).GetComponent<Rigidbody>().linearVelocity; linearVelocity.y = Mathf.Max(linearVelocity.y, __instance.m_jumpForce); Instance._airStepInProgress = true; try { __instance.ForceJump(linearVelocity, true); } finally { Instance._airStepInProgress = false; } if (Instance._vikings.Weightless(val)) { Instance._weightlessUntil = Time.unscaledTime + 3f; } } } } [HarmonyPatch(typeof(Player), "OnJump")] private static class AirStepCostPatch { private static bool Prefix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { Plugin? instance = Instance; if (instance == null) { return true; } return !instance._airStepInProgress; } return true; } } private sealed class ClassRow { internal RectTransform Rect; internal Image Background; internal Image Icon; internal Image Accent; internal TMP_Text Name; internal TMP_Text Status; internal ClassDefinition? Definition; } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] private static class ClassResourceCapacityPatch { private static void Postfix(Player __instance, ref float hp, ref float stamina) { Progression val = (((Object)(object)Instance == (Object)null) ? null : ActiveState((Character)(object)__instance, Instance._state.ClassId)); if (val != null) { hp += ClassResources.Health(val); stamina += ClassResources.Stamina(val); } } } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] private static class BlockTalentPatch { private static void Prefix(HitData hit, out float __state) { __state = hit.GetTotalBlockableDamage(); } private static void Postfix(Humanoid __instance, HitData hit, Character attacker, bool __result, float __state) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown Progression val = ActiveState((Character)(object)__instance); if (val != null && __result && EnemyHit((Character)(object)__instance, attacker) && ((Character)__instance).HaveStamina(0f) && !((Character)__instance).IsStaggering() && !(hit.GetTotalBlockableDamage() >= __state)) { float num = Instance._combat.OnBlock(val, (double)Time.unscaledTime); if (num > 0f) { ((Character)__instance).AddStamina(num); Instance.ShieldPulse((Player)__instance); } } } } [HarmonyPatch(typeof(SEMan), "ModifyAttack")] private static class MeleeTalentPatch { private static void Postfix(Character ___m_character, SkillType skill, ref HitData hitData) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Progression val = ActiveState(___m_character); if (val != null && IsMelee(skill) && !hitData.m_ranged && !(hitData.GetTotalDamage() <= 0f)) { Character val2 = (((Object)(object)hitData.m_hitCollider != (Object)null) ? ((Component)hitData.m_hitCollider).GetComponentInParent<Character>() : null); bool num = (Object)(object)val2 != (Object)null && val2.GetHealth() > 0f && EnemyHit(___m_character, val2); bool flag = Instance._combat.IsRiposteReady(val, (double)Time.unscaledTime); ((DamageTypes)(ref hitData.m_damage)).Modify(Instance._combat.MeleeDamage(val, (double)Time.unscaledTime)); if (num && Instance._combat.IsCritical(val, (double)Time.unscaledTime, (double)Random.value)) { ((DamageTypes)(ref hitData.m_damage)).Modify(1.5f); Instance.CriticalNotice(); } if (num && flag && !val2.IsDodgeInvincible()) { Instance.BeginBleed(val2, hitData.GetTotalDamage()); } if (val.Has("leverage")) { HitData obj = hitData; obj.m_staggerMultiplier *= 1.1f; } } } } [HarmonyPatch(typeof(SEMan), "ModifyRunStaminaDrain")] private static class RunTalentPatch { private static void Postfix(Character ___m_character, ref float drain) { Progression val = ActiveState(___m_character); if (val != null && drain > 0f) { drain *= Instance._combat.RunCost(val, (double)Time.unscaledTime); } } } [HarmonyPatch(typeof(SEMan), "ModifyDodgeStaminaUsage")] private static class DodgeTalentPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression? obj = ActiveState(___m_character); if (obj != null && obj.Has("footwork") && staminaUse > 0f) { staminaUse *= 0.95f; } } } [HarmonyPatch(typeof(SEMan), "ModifyJumpStaminaUsage")] private static class JumpTalentPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression? obj = ActiveState(___m_character); if (obj != null && obj.Has("lightstep") && staminaUse > 0f) { staminaUse *= 0.9f; } } } [HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")] private static class StaminaRegenTalentPatch { private static void Postfix(Character ___m_character, ref float staminaMultiplier) { Progression? obj = ActiveState(___m_character); if (obj != null && obj.Has("breath")) { staminaMultiplier *= 1.03f; } } } [HarmonyPatch(typeof(SEMan), "ModifyHealthRegen")] private static class HealthRegenTalentPatch { private static void Postfix(Character ___m_character, ref float regenMultiplier) { Progression? obj = ActiveState(___m_character); if (obj != null && obj.Has("recuperation")) { regenMultiplier *= 1.05f; } } } [HarmonyPatch(typeof(Character), "AddStaggerDamage")] private static class StaggerTalentPatch { private static void Prefix(Character __instance, ref float damage) { Progression val = ActiveState(__instance); if (val != null && damage > 0f) { damage *= Instance._combat.Stagger(val, (double)Time.unscaledTime); } } } [HarmonyPatch(typeof(Player), "GetBodyArmor")] private static class ArmourTalentPatch { private static void Postfix(Player __instance, ref float __result) { Progression? obj = ActiveState((Character)(object)__instance); if (obj != null && obj.Has("ironhide")) { __result += 2f; } } } [HarmonyPatch(typeof(SEMan), "OnDamaged")] private static class GritTalentPatch { private static void Prefix(Character ___m_character, HitData hit, Character attacker) { Progression? obj = ActiveState(___m_character); if (obj != null && obj.Has("grit") && EnemyHit(___m_character, attacker)) { hit.m_damage.m_blunt *= 0.98f; hit.m_damage.m_slash *= 0.98f; hit.m_damage.m_pierce *= 0.98f; } } } [HarmonyPatch(typeof(Player), "OnDamaged")] private static class WoundedTalentPatch { private static void Postfix(Player __instance, HitData hit) { Progression val = ActiveState((Character)(object)__instance); if (val != null && !(hit.GetTotalDamage() <= 0f) && EnemyHit((Character)(object)__instance, hit.GetAttacker())) { if (Instance._combat.OnWounded(val, (double)Time.unscaledTime, ((Character)__instance).GetHealthPercentage())) { ((Character)__instance).Heal(8f, false); ((Character)__instance).AddStamina(20f); } float num = Instance._combat.Retaliation(val, (double)Time.unscaledTime, hit.GetTotalDamage()); if (num > 0f) { Instance.DealBonusHit(__instance, hit.GetAttacker(), num, bleed: false); } } } } [HarmonyPatch(typeof(Player), "OnDeath")] private static class PlayerDeathPenaltyPatch { private static void Prefix(Player __instance) { try { Instance?.ApplyPlayerDeath(__instance); } catch (Exception ex) { Plugin? instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogError((object)("Warrior death penalty failed: " + ex)); } } } } [HarmonyPatch(typeof(Player), "OnRespawn")] private static class PlayerRespawnPenaltyPatch { private static void Postfix(Player __instance) { Instance?._penalizedDeaths.Remove(__instance); } } private sealed class DefenseStaggerStamp { public int Frame = -1; } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] private static class DefenseBlockPatch { private static void Prefix(HitData hit, out float __state) { __state = hit.GetTotalBlockableDamage(); } private static void Postfix(Humanoid __instance, HitData hit, Character attacker, bool __result, float __state) { Plugin instance = Instance; if ((Object)(object)instance == (Object)null) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val == null) { return; } Progression val2 = ActiveState((Character)(object)val, instance._state.ClassId); float num = __state - hit.GetTotalBlockableDamage(); if (val2 == null || !__result || num <= 0f || !EnemyHit((Character)(object)val, attacker) || !((Character)val).HaveStamina(0f) || ((Character)val).IsStaggering()) { return; } instance._defense.SetMaximumHealth(((Character)val).GetMaxHealth()); float num2 = instance._defense.Block(val2, Time.unscaledTime, num, HasMeleeWeapon((Character)(object)val), HasShield((Character)(object)val)); instance.ObserveDefenseReady(val); if (!(num2 <= 0f)) { instance.GrantDefenseShelter(val, num2); Player[] array = instance.NearbyVikingAllies(val, 8f, 2); foreach (Player target in array) { instance.GrantDefenseShelter(target, num2); } } } } [HarmonyPatch(typeof(Character), "Awake")] private static class DefenseStrikeReceiverPatch { private static void Postfix(Character __instance) { Player player = (Player)(object)((__instance is Player) ? __instance : null); if (player == null) { return; } ZNetView view = ((Component)player).GetComponent<ZNetView>(); if ((Object)(object)view == (Object)null || !view.IsValid()) { return; } view.Register<ZDOID, float, bool>("Oathbound_DefenseStrike_1", (Action<long, ZDOID, float, bool>)delegate(long sender, ZDOID id, float lost, bool staggered) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player != (Object)(object)Player.m_localPlayer) && view.IsOwner() && !(lost <= 0f) && !float.IsNaN(lost) && !float.IsInfinity(lost)) { ZNetScene instance = ZNetScene.instance; object obj; if (instance == null) { obj = null; } else { GameObject obj2 = instance.FindInstance(id); obj = ((obj2 != null) ? obj2.GetComponent<Character>() : null); } Character val = (Character)obj; ZNetView val2 = ((val != null) ? ((Component)val).GetComponent<ZNetView>() : null); if (!((Object)(object)val2 == (Object)null) && val2.IsValid() && val2.GetZDO().GetOwner() == sender) { Instance?.ConfirmDefenseStrike(val, lost, staggered); } } }); } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class DefenseStrikePatch { private static void Prefix(Character __instance, out float __state) { __state = Mathf.Max(0f, __instance.GetHealth()); } private static void Postfix(Character __instance, HitData hit, float __state) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Invalid comparison between Unknown and I4 //IL_0148: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || hit.m_ranged || ((int)hit.m_skill != 7 && (int)hit.m_skill != 11)) { return; } Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (val == null || !EnemyHit((Character)(object)val, __instance)) { return; } float num = __state - Mathf.Max(0f, __instance.GetHealth()); if (num <= 0f) { return; } ZNetView component2 = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)component2 == (Object)null || !component2.IsValid()) { return; } object obj; if (!((Object)(object)val == (Object)(object)Player.m_localPlayer)) { obj = component2.GetZDO().GetString("oathbound.defense.class", ""); } else { Plugin? instance = Instance; obj = ((instance != null) ? instance._state.ClassId : null) ?? ""; } string text = (string)obj; if ((int)hit.m_skill != ((text == "monk") ? 11 : 7)) { return; } if ((Object)(object)val == (Object)(object)Player.m_localPlayer) { Instance?.ConfirmDefenseStrike(__instance, num, DefenseStaggered(__instance)); return; } switch (text) { case "berserker": case "breaker": case "monk": component2.InvokeRPC("Oathbound_DefenseStrike_1", new object[3] { __instance.GetZDOID(), num, DefenseStaggered(__instance) }); break; } } } [HarmonyPatch(typeof(Character), "AddStaggerDamage")] private static class DefenseStaggerPatch { private static void Postfix(Character __instance, bool __result) { if (__result && !__instance.IsPlayer()) { DefenseStaggers.GetValue(__instance, (Character _) => new DefenseStaggerStamp()).Frame = Time.frameCount; } } private static bool Prefix(Character __instance, float damage) { Progression val = ActiveState(__instance, "breaker"); int num; if (val != null) { num = (Instance._defense.PreventStagger(val, Time.unscaledTime, WieldsTwoHandedAxe(__instance)) ? 1 : 0); if (num != 0 && damage > 0f) { Player val2 = (Player)(object)((__instance is Player) ? __instance : null); if (val2 != null) { Instance.DefenseImpactVfx(val2, broken: false); } } } else { num = 0; } return num == 0; } } [HarmonyPatch(typeof(Character), "ApplyDamage")] private static class DefenseDamagePatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { int totals = 0; MethodInfo total = AccessTools.Method(typeof(HitData), "GetTotalDamage", (Type[])null, (Type[])null); MethodInfo resolve = AccessTools.Method(typeof(DefenseDamagePatch), "Resolve", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { yield return instruction; if (CodeInstructionExtensions.Calls(instruction, total)) { int num = totals + 1; totals = num; if (num == 2) { yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null); yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null); yield return new CodeInstruction(OpCodes.Call, (object)resolve); } } } if (totals != 2) { throw new InvalidOperationException("Native ApplyDamage total reads changed; defense hook requires review."); } } private static float Resolve(float damage, Character target, HitData hit) { //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Invalid comparison between Unknown and I4 //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Invalid comparison between Unknown and I4 //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_0339: 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_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Expected O, but got Unknown //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) Plugin instance = Instance; if (!((Object)(object)instance == (Object)null)) { Player val = (Player)(object)((target is Player) ? target : null); if (val != null && ActiveState((Character)(object)val, instance._state.ClassId) != null && !((Character)val).IsDebugFlying() && !((Character)val).IsDead() && !((Character)val).IsTeleporting() && !((Character)val).InCutscene() && !CinematicsManager.IsPlaying()) { ZNetView component = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return damage; } if (damage <= 0.1f || float.IsNaN(damage) || float.IsInfinity(damage)) { return damage; } int num = DefenseTree.Rank(instance._state); if (num == 0) { return damage; } ItemData currentWeapon = ((Humanoid)val).GetCurrentWeapon(); bool flag = true; switch (instance._state.ClassId) { case "huscarl": flag = HasMeleeWeapon((Character)(object)val); break; case "monk": flag = currentWeapon == null || (int)currentWeapon.m_shared.m_skillType == 11; break; case "berserker": flag = WieldsPairedAxes((Character)(object)val); break; case "highlander": flag = WieldsGreatsword((Character)(object)val); break; case "breaker": flag = WieldsTwoHandedAxe((Character)(object)val); break; } Character val2 = ((instance._state.ClassId == "hunter") ? instance.CurrentHunterPet() : ((instance._state.ClassId == "dragonsworn") ? instance.CurrentDragonPet() : null)); bool flag2 = ((instance._state.ClassId == "hunter") ? instance.DefenseCompanionNear(val, val2, "oathbound.hunter.owner", "oathbound.hunter.token", instance._hunterToken, DefenseTree.CompanionRange(num)) : (instance._state.ClassId == "dragonsworn" && instance.DefenseCompanionNear(val, val2, "oathbound.dragon.owner", "oathbound.dragon.token", instance._dragonToken, DefenseTree.CompanionRange(num)))); DefenseContext val3 = default(DefenseContext); ((DefenseContext)(ref val3))..ctor(((Character)val).GetHealthPercentage(), val.GetEitr(), val.GetStamina(), ((Character)val).IsBlocking(), HasShield((Character)(object)val), (int)hit.m_hitType == 3 || (!((Character)val).IsOnGround() && !((Character)val).IsSwimming()), ((Character)val).InAttack(), ((Character)val).IsStaggering(), flag, flag2, instance._dragonFlight.Height); instance._defense.SetMaximumHealth(((Character)val).GetMaxHealth()); instance._defense.Tick(instance._state, Time.unscaledTime); float num2 = ((instance._state.ClassId == "warlock") ? instance._defense.WardRemaining : instance._defense.GuardRemaining); DefenseResult val4 = instance._defense.Resolve(instance._state, Time.unscaledTime, damage, val3); if (val4.EitrSpent > 0f) { DefenseUseEitr.Invoke(val, new object[2] { 0L, val4.EitrSpent }); } if (val4.AltitudeSpent > 0f) { instance._dragonFlight.Intercept(val4.AltitudeSpent); } ((DamageTypes)(ref hit.m_damage)).Modify(val4.Damage / damage); if (damage - val4.Damage > 0.1f) { float num3 = ((instance._state.ClassId == "warlock") ? instance._defense.WardRemaining : instance._defense.GuardRemaining); bool broken = ((!(instance._state.ClassId == "mage")) ? (num2 > 0f && num3 <= 0f) : (val4.EitrSpent > 0f && val.GetEitr() <= 0.01f)); instance.DefenseImpactVfx(val, broken, (val4.Shared > 0f || val4.AltitudeSpent > 0f) ? val2 : null); } instance.ObserveDefenseReady(val); if (val4.Shared > 0f && (Object)(object)val2 != (Object)null) { HitData val5 = new HitData { m_point = val2.GetCenterPoint(), m_blockable = false, m_dodgeable = false }; val5.m_damage.m_damage = val4.Shared; val2.Damage(val5); } return val4.Damage; } } return damage; } } [HarmonyPatch(typeof(Character), "Awake")] private static class DragonAwakePatch { private static void Postfix(Character __instance) { ZNetView view = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)view == (Object)null || !view.IsValid()) { return; } if (IsDragonWhelp(__instance) && (Object)(object)((Component)__instance).GetComponent<DragonWhelp>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<DragonWhelp>(); } Player p = (Player)(object)((__instance is Player) ? __instance : null); if (p == null) { return; } view.Register<ZDOID, string, ZDOID, float>("Oathbound_DragonEvent_1", (Method<ZDOID, string, ZDOID, float>)delegate(long sender, ZDOID pet, string token, ZDOID target, float damage) { //IL_002a: 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) if ((Object)(object)p == (Object)(object)Player.m_localPlayer && view.IsOwner()) { Instance?.OnDragonEvent(sender, pet, token, target, damage); } }); } } [HarmonyPatch(typeof(Character), "OnDeath")] private static class DragonDeathPatch { private static void Prefix(Character __instance) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) if (!IsDragonWhelp(__instance)) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (component.IsOwner()) { ZDO zDO = component.GetZDO(); GameObject obj = ZNetScene.instance.FindInstance(zDO.GetZDOID("oathbound.dragon.owner")); if (obj != null) { obj.GetComponent<ZNetView>().InvokeRPC("Oathbound_DragonEvent_1", new object[4] { __instance.GetZDOID(), zDO.GetString("oathbound.dragon.token", ""), ZDOID.None, 0f }); } } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class DragonStrikePatch { private static void Prefix(Character __instance, out float __state) { __state = __instance.GetHealth(); } private static void Postfix(Character __instance, HitData hit, float __state) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) Character attacker = hit.GetAttacker(); if (IsDragonWhelp(attacker) && ((Component)__instance).GetComponent<ZNetView>().IsOwner()) { Player val = DragonKillOwner(attacker); float num = Mathf.Max(0f, __state - Mathf.Max(0f, __instance.GetHealth())); if (!((Object)(object)val == (Object)null) && !(num <= 0f) && EnemyHit((Character)(object)val, __instance)) { ((Component)val).GetComponent<ZNetView>().InvokeRPC("Oathbound_DragonEvent_1", new object[4] { attacker.GetZDOID(), ((Component)attacker).GetComponent<ZNetView>().GetZDO().GetString("oathbound.dragon.token", ""), __instance.GetZDOID(), num }); } } } } [HarmonyPatch(typeof(SEMan), "ModifyAttack")] private static class DragonWhelpDamagePatch { private static void Postfix(Character ___m_character, ref HitData hitData) { if (IsDragonWhelp(___m_character)) { Player? obj = DragonKillOwner(___m_character); ZDO val = ((obj != null) ? ((Component)obj).GetComponent<ZNetView>().GetZDO() : null); float totalDamage = hitData.GetTotalDamage(); if (totalDamage > 0f) { hitData.ApplyModifier((val != null) ? (Mathf.Clamp(val.GetFloat("oathbound.dragon.damage", 12f), 12f, DragonTree.MaxDamage) / totalDamage) : 0f); } HitData obj2 = hitData; obj2.m_staggerMultiplier *= ((val != null) ? Mathf.Clamp(val.GetFloat("oathbound.dragon.stagger", 1f), 1f, DragonTree.MaxStagger) : 1f); } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class DragonGuardPatch { private static void Prefix(Character __instance, HitData hit) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) if (hit == null || !IsDragonWhelp(__instance)) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return; } ZDO zDO = component.GetZDO(); GameObject obj = ZNetScene.instance.FindInstance(zDO.GetZDOID("oathbound.dragon.owner")); Player val = ((obj != null) ? obj.GetComponent<Player>() : null); object obj2; if (val == null) { obj2 = null; } else { ZNetView component2 = ((Component)val).GetComponent<ZNetView>(); obj2 = ((component2 != null) ? component2.GetZDO() : null); } ZDO val2 = (ZDO)obj2; if (val2 != null && !(val2.GetString("oathbound.dragon.token", "") != zDO.GetString("oathbound.dragon.token", ""))) { float num = Mathf.Clamp(val2.GetFloat("oathbound.dragon.guard", 1f), 0.4f, 1f); if (num < 1f) { hit.ApplyModifier(num); } float num2 = val2.GetFloat("oathbound.dragon.refusal", -1f); DragonWhelp component3 = ((Component)__instance).GetComponent<DragonWhelp>(); if (!(num2 < -0.5f) && !(num2 > 0.5f) && !((Object)(object)component3 == (Object)null) && !(__instance.GetHealth() <= 0f) && !(Time.unscaledTime - component3.RefusedAt < 10f) && !(hit.GetTotalDamage() < __instance.GetHealth())) { component3.RefusedAt = Time.unscaledTime; hit.ApplyModifier(0f); __instance.SetHealth(Mathf.Max(1f, __instance.GetMaxHealth() * 0.5f)); ((Component)val).GetComponent<ZNetView>().InvokeRPC("Oathbound_DragonEvent_1", new object[4] { __instance.GetZDOID(), zDO.GetString("oathbound.dragon.token", ""), ZDOID.None, -1f }); } } } } [HarmonyPatch(typeof(Player), "Load")] private static class DragonLoadPatch { private static void Prefix(Player __instance) { if ((Object)(object)Instance?._player == (Object)(object)__instance) { Instance.StowDragon(); } } } [HarmonyPatch(typeof(SEMan), "ModifyRunStaminaDrain")] private static class DragonRunPatch { private static void Postfix(Character ___m_character, ref float drain) { Progression val = ActiveState(___m_character, "dragonsworn"); if (val != null && !(drain <= 0f)) { drain *= 1f - DragonTree.Value(val, (Bonus)6); if (val.Has("dg_chase_free") && Time.unscaledTime < Instance._dragonChaseUntil) { drain = 0f; } } } } [HarmonyPatch(typeof(SEMan), "ModifySneakStaminaUsage")] private static class DragonSneakPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character, "dragonsworn"); if (val != null && staminaUse > 0f) { staminaUse *= 1f - DragonTree.Value(val, (Bonus)1); } } } [HarmonyPatch(typeof(SEMan), "ModifyDodgeStaminaUsage")] private static class DragonDodgePatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character, "dragonsworn"); if (val != null && !(staminaUse <= 0f)) { staminaUse *= 1f - DragonTree.Value(val, (Bonus)5); if (val.Has("dg_chase_free") && Time.unscaledTime < Instance._dragonChaseUntil) { staminaUse = 0f; } } } } [HarmonyPatch(typeof(SEMan), "ModifyJumpStaminaUsage")] private static class DragonJumpPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character, "dragonsworn"); if (val != null && staminaUse > 0f) { staminaUse *= 1f - DragonTree.Value(val, (Bonus)10); } } } [HarmonyPatch(typeof(SEMan), "ModifyAttackStaminaUsage")] private static class DragonBowCostPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) Progression val = ActiveState(___m_character, "dragonsworn"); Character obj = ((___m_character is Humanoid) ? ___m_character : null); ItemData val2 = ((obj != null) ? ((Humanoid)obj).GetCurrentWeapon() : null); if (val != null && val2 != null && IsDragonBow(val2.m_shared.m_skillType) && staminaUse > 0f) { staminaUse *= 1f - DragonTree.Value(val, (Bonus)12); } } } [HarmonyPatch(typeof(SEMan), "ModifyAttack")] private static class DragonShotPatch { private static void Postfix(Character ___m_character, SkillType skill, ref HitData hitData) { //IL_001a: 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_005e: Unknown result type (might be due to invalid IL or missing references) Progression val = (IsDragonWhelp(___m_character) ? null : ActiveState(___m_character, "dragonsworn")); if (val != null && IsDragonBow(skill) && !(hitData.GetTotalDamage() <= 0f)) { DragonTuning val2 = default(DragonTuning); ((DragonTuning)(ref val2))..ctor(val); if (val2.CeilingShot > 0f && Instance.AtCeiling()) { ((DamageTypes)(ref hitData.m_damage)).Modify(1f + val2.CeilingShot); } } } } [HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")] private static class DragonStaminaPatch { private static void Postfix(Character ___m_character, ref float staminaMultiplier) { Progression val = ActiveState(___m_character, "dragonsworn"); if (val != null) { staminaMultiplier *= 1f + DragonTree.Value(val, (Bonus)8); if (val.Has("dg_over_calm") && Instance.AtCeiling()) { staminaMultiplier *= 1.25f; } } } } [HarmonyPatch(typeof(SEMan), "ModifyHealthRegen")] private static class DragonHealthPatch { private static void Postfix(Character ___m_character, ref float regenMultiplier) { Progression val = ActiveState(___m_character, "dragonsworn"); if (val != null) { regenMultiplier *= 1f + DragonTree.Value(val, (Bonus)9); } } } [HarmonyPatch(typeof(Character), "AddStaggerDamage")] private static class DragonStaggerPatch { private static void Prefix(Character __instance, ref float damage) { Progression val = ActiveState(__instance, "dragonsworn"); if (val != null && damage > 0f) { damage *= 1f - DragonTree.Value(val, (Bonus)7); } } } [HarmonyPatch(typeof(SEMan), "ModifyFallDamage")] private static class DragonFallPatch { private static void Postfix(Character ___m_character, ref float damage) { Progression val = ActiveState(___m_character, "dragonsworn"); if (val != null && damage > 0f && val.Has("dg_over_fall") && Instance.AtCeiling()) { damage = 0f; } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class DragonFrostPatch { private static void Prefix(Character __instance, HitData hit) { if (hit == null || hit.m_damage.m_frost <= 0f) { return; } Progression val = ActiveState(__instance, "dragonsworn"); if (val != null) { float num = DragonTree.Value(val, (Bonus)29); if (num > 0f) { hit.m_damage.m_frost *= Mathf.Clamp01(1f - num); } } } } [HarmonyPatch(typeof(Character), "Damage")] private static class DragonMarkPatch { private static void Prefix(Character __instance, HitData hit) { //IL_003b: 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_0076: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) Plugin instance = Instance; Character obj = ((hit != null) ? hit.GetAttacker() : null); Player val = (Player)(object)((obj is Player) ? obj : null); if ((Object)(object)instance == (Object)null || hit == null || (Object)(object)val == (Object)null || ActiveState((Character)(object)val, "dragonsworn") == null || (int)hit.m_skill == 0 || !EnemyHit((Character)(object)Player.m_localPlayer, __instance)) { return; } DragonTuning val2 = default(DragonTuning); ((DragonTuning)(ref val2))..ctor(instance._state); if (instance._state.Has("dg_mark") && instance._dragonMark == __instance.GetZDOID() && Time.unscaledTime < instance._dragonMarkUntil) { hit.ApplyModifier(val2.MarkBonus); } if (instance._state.Has("dg_hoar") && instance.Rimed(__instance)) { hit.ApplyModifier(val2.RimeAmp); if (val2.RimeShatters && !(__instance.GetMaxHealth() <= 0f) && !(__instance.GetHealth() > __instance.GetMaxHealth() / 3f)) { hit.ApplyModifier(1.4f); __instance.GetSEMan().RemoveStatusEffect(DragonRime.Hash, true); instance.Notify("Shatter."); } } } } [HarmonyPatch(typeof(SEMan), "ModifyAttack")] private static class HighlanderHeftPatch { private static void Postfix(Character ___m_character, SkillType skill, HitData hitData) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 Progression val = ActiveState(___m_character, "highlander"); if (val != null && WieldsGreatsword(___m_character) && (int)skill == 1 && !hitData.m_ranged) { Instance._martial.OnAttack(val, (double)Time.unscaledTime); } } } [HarmonyPatch(typeof(Character), "Heal")] private static class MortalWoundPatch { private static bool Prefix(Character __instance, float hp) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) Plugin instance = Instance; if ((Object)(object)instance == (Object)null || !((Behaviour)instance).enabled || !instance.CanProgress || hp <= 0f || __instance is Player) { return true; } Progression state = instance._state; if (state.ClassId != "highlander" && state.ClassId != "breaker") { return true; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return true; } return !instance._martial.Denied(((object)__instance.GetZDOID()/*cast due to .constrained prefix*/).ToString(), (double)Time.unscaledTime); } } [HarmonyPatch(typeof(Character), "AddPushbackForce")] private static class MartialPushbackPatch { private static bool Prefix(Character __instance) { Plugin instance = Instance; if ((Object)(object)instance == (Object)null || !((Behaviour)instance).enabled || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } Progression val = MartialState(__instance); if (val == null) { return true; } double num = Time.unscaledTime; if (val.ClassId == "highlander") { return !instance._martial.ResolveUnpushed(val, num); } if (val.ClassId == "breaker") { return !instance._martial.Unmoved(val); } return true; } } [HarmonyPatch(typeof(Character), "Awake")] private static class HunterAwakePatch { private static void Postfix(Character __instance) { ZNetView view = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)view == (Object)null || !view.IsValid()) { return; } if (IsHunterPet(__instance) && (Object)(object)((Component)__instance).GetComponent<HunterCompanion>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<HunterCompanion>(); } Player p = (Player)(object)((__instance is Player) ? __instance : null); if (p == null) { return; } view.Register<ZDOID, string, ZDOID, float>("Oathbound_HunterEvent_1", (Method<ZDOID, string, ZDOID, float>)delegate(long sender, ZDOID pet, string token, ZDOID target, float damage) { //IL_002a: 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) if ((Object)(object)p == (Object)(object)Player.m_localPlayer && view.IsOwner()) { Instance?.OnHunterEvent(sender, pet, token, target, damage); } }); } } [HarmonyPatch(typeof(Character), "OnDeath")] private static class HunterDeathPatch { private static void Prefix(Character __instance) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) if (!IsHunterPet(__instance)) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (component.IsOwner()) { ZDO zDO = component.GetZDO(); GameObject obj = ZNetScene.instance.FindInstance(zDO.GetZDOID("oathbound.hunter.owner")); if (obj != null) { obj.GetComponent<ZNetView>().InvokeRPC("Oathbound_HunterEvent_1", new object[4] { __instance.GetZDOID(), zDO.GetString("oathbound.hunter.token", ""), ZDOID.None, 0f }); } } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class HunterBitePatch { private static void Prefix(Character __instance, out float __state) { __state = __instance.GetHealth(); } private static void Postfix(Character __instance, HitData hit, float __state) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) Character attacker = hit.GetAttacker(); if (IsHunterPet(attacker) && ((Component)__instance).GetComponent<ZNetView>().IsOwner()) { Player val = HunterKillOwner(attacker); float num = Mathf.Max(0f, __state - Mathf.Max(0f, __instance.GetHealth())); if (!((Object)(object)val == (Object)null) && !(num <= 0f) && EnemyHit((Character)(object)val, __instance)) { ((Component)val).GetComponent<ZNetView>().InvokeRPC("Oathbound_HunterEvent_1", new object[4] { attacker.GetZDOID(), ((Component)attacker).GetComponent<ZNetView>().GetZDO().GetString("oathbound.hunter.token", ""), __instance.GetZDOID(), num }); } } } } [HarmonyPatch(typeof(Character), "Damage")] private static class HunterPackPatch { private static void Prefix(Character __instance, HitData hit) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Invalid comparison between Unknown and I4 //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Invalid comparison between Unknown and I4 //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) Plugin instance = Instance; Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if ((Object)(object)instance == (Object)null || (Object)(object)val == (Object)null || ActiveState((Character)(object)val, "hunter") == null || (int)hit.m_skill == 0 || !EnemyHit((Character)(object)Player.m_localPlayer, __instance)) { return; } HunterTuning val2 = default(HunterTuning); ((HunterTuning)(ref val2))..ctor(instance._state); if (instance._state.Has("h_pack") && instance._hunterMark == __instance.GetZDOID() && Time.unscaledTime < instance._hunterMarkUntil) { hit.ApplyModifier(val2.MarkBonus); if (val2.MarkStaggers) { hit.m_staggerMultiplier *= 1.5f; } } if (val2.LooseOnShot && ((int)hit.m_skill == 8 || (int)hit.m_skill == 14) && __instance.GetHealth() > 0f) { Character val3 = instance.CurrentHunterPet(); if ((Object)(object)val3 != (Object)null && val3.GetHealth() > 0f) { instance.SetUponHunter(val, val3, __instance, val2, announce: false); } } } } [HarmonyPatch(typeof(SEMan), "ModifyAttack")] private static class HunterDamagePatch { private static void Postfix(Character ___m_character, ref HitData hitData) { if (IsHunterPet(___m_character)) { Player? obj = HunterKillOwner(___m_character); ZDO val = ((obj != null) ? ((Component)obj).GetComponent<ZNetView>().GetZDO() : null); float totalDamage = hitData.GetTotalDamage(); if (totalDamage > 0f) { hitData.ApplyModifier((val != null) ? (Mathf.Clamp(val.GetFloat("oathbound.hunter.damage", 10f), 10f, HunterTree.MaxDamage) / totalDamage) : 0f); } HitData obj2 = hitData; obj2.m_staggerMultiplier *= ((val != null) ? Mathf.Clamp(val.GetFloat("oathbound.hunter.stagger", 1f), 1f, HunterTree.MaxStagger) : 1f); } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class HunterGuardPatch { private static void Prefix(Character __instance, HitData hit) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) if (hit == null || !IsHunterPet(__instance)) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return; } ZDO zDO = component.GetZDO(); GameObject obj = ZNetScene.instance.FindInstance(zDO.GetZDOID("oathbound.hunter.owner")); Player val = ((obj != null) ? obj.GetComponent<Player>() : null); object obj2; if (val == null) { obj2 = null; } else { ZNetView component2 = ((Component)val).GetComponent<ZNetView>(); obj2 = ((component2 != null) ? component2.GetZDO() : null); } ZDO val2 = (ZDO)obj2; if (val2 != null && !(val2.GetString("oathbound.hunter.token", "") != zDO.GetString("oathbound.hunter.token", ""))) { float num = Mathf.Clamp(val2.GetFloat("oathbound.hunter.guard", 1f), 0.45f, 1f); if (num < 1f) { hit.ApplyModifier(num); } float num2 = val2.GetFloat("oathbound.hunter.rally", -1f); HunterCompanion component3 = ((Component)__instance).GetComponent<HunterCompanion>(); if (!(num2 < -0.5f) && !(num2 > 0.5f) && !((Object)(object)component3 == (Object)null) && !(__instance.GetHealth() <= 0f) && !(Time.unscaledTime - component3.RalliedAt < 10f) && !(hit.GetTotalDamage() < __instance.GetHealth())) { component3.RalliedAt = Time.unscaledTime; hit.ApplyModifier(0f); __instance.SetHealth(Mathf.Max(1f, __instance.GetMaxHealth() * 0.5f)); ((Component)val).GetComponent<ZNetView>().InvokeRPC("Oathbound_HunterEvent_1", new object[4] { __instance.GetZDOID(), zDO.GetString("oathbound.hunter.token", ""), ZDOID.None, -1f }); } } } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] private static class HunterLootPatch { private static bool Prefix(CharacterDrop __instance, ref List<KeyValuePair<GameObject, int>> __result) { if (!IsOathboundCompanion(((Component)__instance).GetComponent<Character>())) { return true; } __result = new List<KeyValuePair<GameObject, int>>(); return false; } } [HarmonyPatch(typeof(Procreation), "Procreate")] private static class HunterBreedingPatch { private static bool Prefix(Procreation __instance) { return !IsOathboundCompanion(((Component)__instance).GetComponent<Character>()); } } [HarmonyPatch(typeof(Tameable), "RPC_Command")] private static class HunterCommandPatch { private static bool Prefix(Tameable __instance) { return !IsOathboundCompanion(((Component)__instance).GetComponent<Character>()); } } [HarmonyPatch(typeof(Player), "Load")] private static class HunterLoadPatch { private static void Prefix(Player __instance) { if ((Object)(object)Instance?._player == (Object)(object)__instance) { Instance.StowHunter(); } } } [HarmonyPatch(typeof(SEMan), "ModifyRunStaminaDrain")] private static class HunterRunPatch { private static void Postfix(Character ___m_character, ref float drain) { Progression val = ActiveState(___m_character, "hunter"); if (val != null && !(drain <= 0f)) { drain *= 1f - HunterTree.Value(val, (Bonus)6); if (val.Has("h_end_pack") && Instance.HoundNear(15f)) { drain *= 0.75f; } if (val.Has("h_chase_give") && Time.unscaledTime < Instance._hunterChaseUntil) { drain = 0f; } } } } [HarmonyPatch(typeof(SEMan), "ModifySneakStaminaUsage")] private static class HunterSneakPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character, "hunter"); if (val != null && !(staminaUse <= 0f)) { staminaUse *= 1f - HunterTree.Value(val, (Bonus)1); if (val.Has("h_end_pack") && Instance.HoundNear(15f)) { staminaUse *= 0.75f; } } } } [HarmonyPatch(typeof(SEMan), "ModifyDodgeStaminaUsage")] private static class HunterDodgePatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character, "hunter"); if (val != null && !(staminaUse <= 0f)) { staminaUse *= 1f - HunterTree.Value(val, (Bonus)5); if (val.Has("h_chase_give") && Time.unscaledTime < Instance._hunterChaseUntil) { staminaUse = 0f; } } } } [HarmonyPatch(typeof(SEMan), "ModifyJumpStaminaUsage")] private static class HunterJumpPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character, "hunter"); if (val != null && staminaUse > 0f) { staminaUse *= 1f - HunterTree.Value(val, (Bonus)10); } } } [HarmonyPatch(typeof(SEMan), "ModifySwimStaminaUsage")] private static class HunterSwimPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character, "hunter"); if (val != null && staminaUse > 0f) { staminaUse *= 1f - HunterTree.Value(val, (Bonus)18); } } } [HarmonyPatch(typeof(SEMan), "ModifyAttackStaminaUsage")] private static class HunterBowCostPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) Progression val = ActiveState(___m_character, "hunter"); Character obj = ((___m_character is Humanoid) ? ___m_character : null); ItemData val2 = ((obj != null) ? ((Humanoid)obj).GetCurrentWeapon() : null); if (val != null && val2 != null && IsHunterBow(val2.m_shared.m_skillType) && staminaUse > 0f) { staminaUse *= 1f - HunterTree.Value(val, (Bonus)12); } } } [HarmonyPatch(typeof(SEMan), "ModifyAttack")] private static class HunterShotPatch { private static void Postfix(Character ___m_character, SkillType skill, ref HitData hitData) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Progression val = (IsHunterPet(___m_character) ? null : ActiveState(___m_character, "hunter")); if (val != null && IsHunterBow(skill) && !(hitData.GetTotalDamage() <= 0f)) { ((DamageTypes)(ref hitData.m_damage)).Modify(1f + HunterTree.Value(val, (Bonus)4)); } } } [HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")] private static class HunterStaminaPatch { private static void Postfix(Character ___m_character, ref float staminaMultiplier) { Progression val = ActiveState(___m_character, "hunter"); if (val != null) { staminaMultiplier *= 1f + HunterTree.Value(val, (Bonus)8); if (val.Has("h_share_wind") && Time.unscaledTime < Instance._hunterBiteUntil) { staminaMultiplier *= 1.25f; } } } } [HarmonyPatch(typeof(SEMan), "ModifyHealthRegen")] private static class HunterHealthPatch { private static void Postfix(Character ___m_character, ref float regenMultiplier) { Progression val = ActiveState(___m_character, "hunter"); if (val != null) { regenMultiplier *= 1f + HunterTree.Value(val, (Bonus)9); } } } [HarmonyPatch(typeof(Character), "AddStaggerDamage")] private static class HunterStaggerPatch { private static void Prefix(Character __instance, ref float damage) { Progression val = ActiveState(__instance, "hunter"); if (val != null && damage > 0f) { damage *= 1f - HunterTree.Value(val, (Bonus)7); } } } private sealed class Keybind { public string Button = ""; public string Registered = ""; public string Label = ""; public ConfigEntry<KeyboardShortcut> Entry; public ButtonConfig Config; } [HarmonyPatch(typeof(KeyboardMouseSettings), "Initialize")] private static class KeybindRowsPatch { private static void Postfix(KeyboardMouseSettings __instance) { try { Instance?.AddKeybindRows(__instance); } catch (Exception ex) { Plugin? instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogError((object)("Oathbound keybind rows could not be added: " + ex)); } } } } private sealed class FirePatch { internal Vector3 Point; internal float Radius; internal float Until; internal float NextTick; internal float Damage; } [HarmonyPatch(typeof(Character), "Damage")] private static class MageSpellHitPatch { private static void Prefix(Character __instance, HitData hit) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_016c: 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_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: 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_0180: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) Plugin instance = Instance; Player player = default(Player); ref Player reference = ref player; Character obj = ((hit != null) ? hit.GetAttacker() : null); reference = (Player)(object)((obj is Player) ? obj : null); if ((Object)(object)instance == (Object)null || (Object)(object)player == (Object)null || (int)hit.m_skill != 9) { return; } Progression val = ActiveState((Character)(object)player, "mage"); if (val == null || hit.GetTotalDamage() <= 0f || __instance.GetHealth() <= 0f || !EnemyHit((Character)(object)player, __instance)) { return; } MageTuning val2 = default(MageTuning); ((MageTuning)(ref val2))..ctor(val); ZDOID zDOID = __instance.GetZDOID(); float unscaledTime = Time.unscaledTime; bool num = hit.m_damage.m_fire > 0f; bool flag = hit.m_damage.m_frost > 0f; bool flag2 = hit.m_damage.m_lightning > 0f; if (num && val2.BurnBonus > 0f && instance.Burning(__instance)) { ((DamageTypes)(ref hit.m_damage)).Modify(1f + val2.BurnBonus); } if (flag && val2.ChillBonus > 0f && instance._mageChill.ContainsKey(zDOID)) { ((DamageTypes)(ref hit.m_damage)).Modify(1f + val2.ChillBonus); } if (flag2 && val2.ChargedBonus > 0f && instance._mageCharged.ContainsKey(zDOID)) { ((DamageTypes)(ref hit.m_damage)).Modify(1f + val2.ChargedBonus); } if (flag2 && val2.NearBonus > 0f && Vector3.Distance(((Component)player).transform.position, ((Component)__instance).transform.position) <= 8f) { ((DamageTypes)(ref hit.m_damage)).Modify(1f + val2.NearBonus); } if (val2.Shatters && instance._mageFrozen.ContainsKey(zDOID)) { ((DamageTypes)(ref hit.m_damage)).Modify(1.6f); instance._mageFrozen.Remove(zDOID); __instance.GetSEMan().RemoveStatusEffect(MageFreeze.Hash, true); } if (num && val2.Burns) { instance.BeginBurn(__instance, val2); } if (flag && val2.Chills) { instance.SlowEnemy(__instance); (int, float) value; int num2 = ((!instance._mageChill.TryGetValue(zDOID, out value) || !(unscaledTime <= value.Item2)) ? 1 : (value.Item1 + 1)); instance._mageChill[zDOID] = (num2, unscaledTime + (float)((num2 >= 3) ? 4 : 6)); if (val2.Freezes && num2 >= 3) { instance.FreezeEnemy(__instance); instance._mageChill[zDOID] = (0, unscaledTime + 4f); } } if (flag2 && val2.Charges) { instance._mageCharged[zDOID] = unscaledTime + 4f; } if (!flag2 || !val2.Arcs || instance._mageArcing) { return; } Character val3 = (from c in Character.GetAllCharacters() where (Object)(object)c != (Object)null && (Object)(object)c != (Object)(object)__instance && c.GetHealth() > 0f && EnemyHit((Character)(object)player, c) && Vector3.Distance(__instance.GetCenterPoint(), c.GetCenterPoint()) <= 6f && ClearPath(__instance.GetCenterPoint(), c) select c).OrderBy(delegate(Character c) { //IL_0001: 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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 val4 = c.GetCenterPoint() - __instance.GetCenterPoint(); return ((Vector3)(ref val4)).sqrMagnitude; }).FirstOrDefault(); if (!((Object)(object)val3 != (Object)null)) { return; } instance._mageArcing = true; try { instance.DealBonusHit(player, val3, hit.GetTotalDamage() * 0.5f, bleed: false, piercing: false, fire: false, lightning: true); } finally { instance._mageArcing = false; } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class MageFrailPatch { private static void Prefix(Character __instance, HitData hit) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (hit != null && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { Progression val = ActiveState(__instance, "mage"); if (val != null && val.Has("m_st_frail") && EnemyHit(__instance, hit.GetAttacker())) { hit.ApplyModifier(new MageTuning(val).FrailPenalty); } } } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] private static class MageEitrPatch { private static void Postfix(Player __instance, ref float eitr) { Progression val = ActiveState((Character)(object)__instance, "mage") ?? ActiveState((Character)(object)__instance, "warlock"); if (val != null) { eitr += ClassMagic.Eitr(val); } } } [HarmonyPatch(typeof(SEMan), "ModifyEitrRegen")] private static class MageRegenPatch { private static void Postfix(Character ___m_character, ref float eitrMultiplier) { Progression val = ActiveState(___m_character, "mage") ?? ActiveState(___m_character, "warlock"); if (val != null) { eitrMultiplier *= ClassMagic.Regen(val); } } } [HarmonyPatch(typeof(SEMan), "ModifyAttackStaminaUsage")] private static class MageMeleePatch { private static void Postfix(Character ___m_character, ref float staminaUse) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) Progression val = ActiveState(___m_character, "mage"); Character obj = ((___m_character is Humanoid) ? ___m_character : null); ItemData val2 = ((obj != null) ? ((Humanoid)obj).GetCurrentWeapon() : null); if (val != null && val2 != null && IsMelee(val2.m_shared.m_skillType) && staminaUse > 0f) { staminaUse *= 1f - MageTree.Value(val, (Bonus)12); } } } [HarmonyPatch(typeof(SEMan), "ModifyRunStaminaDrain")] private static class MageRunPatch { private static void Postfix(Character ___m_character, ref float drain) { Progression val = ActiveState(___m_character, "mage"); if (val != null && drain > 0f) { drain *= 1f - MageTree.Value(val, (Bonus)6); } } } [HarmonyPatch(typeof(SEMan), "ModifyJumpStaminaUsage")] private static class MageJumpPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character, "mage"); if (val != null && staminaUse > 0f) { staminaUse *= 1f - MageTree.Value(val, (Bonus)10); } } } [HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")] private static class MageStaminaPatch { private static void Postfix(Character ___m_character, ref float staminaMultiplier) { Progression val = ActiveState(___m_character, "mage"); if (val != null) { staminaMultiplier *= 1f + MageTree.Value(val, (Bonus)8); } } } [HarmonyPatch(typeof(Character), "AddStaggerDamage")] private static class MageStaggerPatch { private static void Prefix(Character __instance, ref float damage) { Progression val = ActiveState(__instance, "mage"); if (val != null && damage > 0f) { damage *= 1f - MageTree.Value(val, (Bonus)7); } } } [HarmonyPatch(typeof(Humanoid), "EquipItem")] private static class ClassEquipPatch { private static bool Prefix(Humanoid __instance, ItemData item, ref bool __result) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || item == null || (Object)(object)Instance == (Object)null) { return true; } if (LoadingEquipment.Contains((Player)__instance)) { return true; } Instance.EnsurePlayer((Player)__instance); if (Instance._loadError != null || Instance.AllowedItem(item)) { return true; } __result = false; Instance.Notify(Instance.Refusal(item)); return false; } private static void Postfix(Humanoid __instance, ItemData item, bool __result) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && item != null && item.m_equipped) { Instance?.DiscoverEquippedClasses((Player)__instance); } } } [HarmonyPatch(typeof(SEMan), "ModifyAttack")] private static class MartialAttackPatch { private static void Postfix(Character ___m_character, SkillType skill, ref HitData hitData) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Invalid comparison between Unknown and I4 Progression val = MartialState(___m_character); if (val == null || hitData.m_ranged || !IsMelee(skill) || hitData.GetTotalDamage() <= 0f) { return; } if (val.ClassId == "rogue" || val.ClassId == "berserker" || val.ClassId == "highlander" || val.ClassId == "breaker") { hitData.ApplyModifier(1f + MartialTrees.Value(val, (Bonus)4)); if (val.ClassId == "berserker" || val.ClassId == "highlander" || val.ClassId == "breaker") { HitData obj = hitData; obj.m_staggerMultiplier *= 1f + MartialTrees.Value(val, (Bonus)13); } } if ((int)skill == 11 && Fists(___m_character)) { hitData.m_damage.m_blunt += MartialTrees.Value(val, (Bonus)11); hitData.ApplyModifier(MartialCombat.MonkFistPower(val)); HitData obj2 = hitData; obj2.m_staggerMultiplier *= 1f + MartialTrees.Value(val, (Bonus)13); } } } [HarmonyPatch(typeof(Character), "Damage")] private static class MartialHitPatch { private static void Prefix(Character __instance, HitData hit) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Invalid comparison between Unknown and I4 //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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_0120: 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_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_0512: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_05a3: Unknown result type (might be due to invalid IL or missing references) //IL_05a8: Unknown result type (might be due to invalid IL or missing references) //IL_05d7: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Unknown result type (might be due to invalid IL or missing references) //IL_0624: Unknown result type (might be due to invalid IL or missing references) Player player = default(Player); ref Player reference = ref player; Character attacker = hit.GetAttacker(); reference = (Player)(object)((attacker is Player) ? attacker : null); Progression val = (((Object)(object)player == (Object)null) ? null : MartialState((Character)(object)player)); if (val == null || hit.m_ranged || !IsMelee(hit.m_skill) || hit.GetTotalDamage() <= 0f || __instance.GetHealth() <= 0f || __instance.IsDodgeInvincible() || !EnemyHit((Character)(object)player, __instance) || (val.ClassId == "monk" && ((int)hit.m_skill != 11 || !Fists((Character)(object)player)))) { return; } bool flag = (Object)(object)__instance.GetBaseAI() != (Object)null && !__instance.GetBaseAI().IsAlerted(); Vector3 forward = ((Component)__instance).transform.forward; Vector3 val2 = ((Component)player).transform.position - ((Component)__instance).transform.position; bool flag2 = Vector3.Dot(forward, ((Vector3)(ref val2)).normalized) < -0.5f; Plugin instance = Instance; bool flag3 = val.ClassId == "rogue" && !((Character)player).IsOnGround() && !((Character)player).IsSwimming(); bool flag4 = ((val.ClassId == "rogue") ? instance.Bleeding(__instance, "q_vein") : (val.ClassId == "berserker" && instance.Bleeding(__instance, "b_rend"))); float num = ((val.ClassId == "highlander") ? Vector3.Distance(((Component)player).transform.position, ((Component)__instance).transform.position) : 0f); string text = ((object)__instance.GetZDOID()/*cast due to .constrained prefix*/).ToString(); float line = instance._martial.ExecuteLine(val, (double)Time.unscaledTime, text); MartialStrike val3 = instance._martial.Strike(val, (double)Time.unscaledTime, text, flag, flag2, flag3, __instance.GetHealthPercentage(), flag4, ((Character)player).GetHealthPercentage(), __instance.IsStaggering(), num); hit.ApplyModifier(val3.Multiplier); hit.m_pushForce += val3.Push; hit.m_staggerMultiplier *= val3.Stagger; if (val3.Unblockable) { hit.m_blockable = false; } if (val3.Wave) { instance.ShieldPulse(player, 3f, val3.Push, slow: false, __instance.GetCenterPoint(), __instance); } if (val3.Third) { if (val.ClassId == "monk") { hit.m_staggerMultiplier *= 2f; } instance.CriticalNotice(); } if (val3.Stamina > 0f) { ((Character)player).AddStamina(val3.Stamina); } if (val3.Bleed) { if (val.ClassId == "berserker") { BerserkerTuning val4 = MartialCombat.BersTune(val); instance.BeginBleed(__instance, hit.GetTotalDamage(), "b_rend", val4.RendCap, val4.RendTicks); } else { RogueTuning val5 = MartialCombat.RogueTune(val); instance.BeginBleed(__instance, hit.GetTotalDamage(), "q_vein", val5.VeinCap, val5.VeinTicks); } } if (val3.Mortal) { instance.Notify("Mortal wound."); } if (val3.Heal > 0f) { ((Character)player).Heal(val3.Heal, false); } if (val3.Execute) { float totalDamage = hit.GetTotalDamage(); bool flag5 = __instance.IsBoss(); float num2 = __instance.GetHealth() - totalDamage; if (val3.Finish && !flag5 && num2 > 0f && num2 < __instance.GetMaxHealth() * MartialCombat.HighTune(val).FinishLine) { hit.m_damage.m_slash += num2 + 1f; totalDamage = hit.GetTotalDamage(); } instance.CriticalNotice(); instance.HighlanderHarvest(player, __instance, totalDamage, val3.FearPulse, val3.Harvest, line); } if (val3.Quake) { float reach = instance._martial.QuakeReach(val); int num3 = instance._martial.SpreadFractures(val); Character[] array = (from c in Character.GetAllCharacters() where (Object)(object)c != (Object)(object)__instance && c.GetHealth() > 0f && EnemyHit((Character)(object)player, c) && Vector3.Distance(c.GetCenterPoint(), __instance.GetCenterPoint()) <= reach select c).ToArray(); foreach (Character val6 in array) { instance._martial.AddFractures(val, ((object)val6.GetZDOID()/*cast due to .constrained prefix*/).ToString(), num3, (double)Time.unscaledTime); } } if (val3.Push > 0f) { int num5 = instance._martial.PushFractures(val); if (num5 > 0) { instance._martial.AddFractures(val, text, num5, (double)Time.unscaledTime); } } if (val3.Shattered) { instance.CriticalNotice(); } if (val3.Sweep) { MonkTuning val7 = MartialCombat.MonkTune(val); bool flag6 = val.ClassId == "berserker" || val.ClassId == "breaker"; float reach2 = (flag6 ? 3f : val7.SweepReach); float damage = (flag6 ? Mathf.Min(10f, hit.GetTotalDamage() * 0.3f) : Mathf.Min(val7.SweepCap, hit.GetTotalDamage() * 0.35f)); int count = (flag6 ? 1 : val7.SweepTargets); Character[] array = (from c in Character.GetAllCharacters() where (Object)(object)c != (Object)(object)__instance && c.GetHealth() > 0f && EnemyHit((Character)(object)player, c) && Vector3.Distance(c.GetCenterPoint(), __instance.GetCenterPoint()) <= reach2 && ClearPath(__instance.GetCenterPoint(), c) select c).OrderBy(delegate(Character c) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Vector3 val8 = ((Component)c).transform.position - ((Component)__instance).transform.position; return ((Vector3)(ref val8)).sqrMagnitude; }).Take(count).ToArray(); foreach (Character enemy in array) { instance.DealBonusHit(player, enemy, damage, bleed: false); } } } } [HarmonyPatch(typeof(SEMan), "ModifyStealth")] private static class RogueStealthPatch { private static void Postfix(Character ___m_character, ref float stealth) { Progression val = ActiveState(___m_character, "rogue"); if (val != null) { stealth *= (1f - MartialTrees.Value(val, (Bonus)2)) * Instance._martial.StealthFactor(val, (double)Time.unscaledTime); } } } [HarmonyPatch(typeof(SEMan), "ModifyNoise")] private static class RogueNoisePatch { private static void Postfix(Character ___m_character, ref float noise) { Progression val = ActiveState(___m_character, "rogue"); if (val != null) { noise *= (1f - MartialTrees.Value(val, (Bonus)3)) * Instance._martial.NoiseFactor(val, (double)Time.unscaledTime); } } } [HarmonyPatch(typeof(SEMan), "ModifySneakStaminaUsage")] private static class MartialSneakPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { staminaUse *= 1f - MartialBonus(___m_character, (Bonus)1); } } [HarmonyPatch(typeof(SEMan), "ModifyDodgeStaminaUsage")] private static class MartialDodgePatch { private static void Postfix(Character ___m_character, ref float staminaUse) { staminaUse *= 1f - MartialBonus(___m_character, (Bonus)5); Progression val = ActiveState(___m_character, "rogue"); if (val != null && val.Has("q_hard_corner") && ___m_character.GetHealthPercentage() < 0.3f) { staminaUse = 0f; } } } [HarmonyPatch(typeof(Character), "GetEquipmentMovementModifier")] private static class MartialBurdenPatch { private static void Postfix(Character __instance, ref float __result) { if (!(__result >= 0f)) { float num = MartialBonus(__instance, (Bonus)28); if (!(num <= 0f)) { __result *= 1f - Mathf.Min(1f, num); } } } } [HarmonyPatch(typeof(SEMan), "ModifyRunStaminaDrain")] private static class MartialRunPatch { private static void Postfix(Character ___m_character, ref float drain) { drain *= 1f - MartialBonus(___m_character, (Bonus)6); } } [HarmonyPatch(typeof(SEMan), "ModifyJumpStaminaUsage")] private static class MartialJumpPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { staminaUse *= 1f - MartialBonus(___m_character, (Bonus)10); } } [HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")] private static class MartialRegenPatch { private static void Postfix(Character ___m_character, ref float staminaMultiplier) { staminaMultiplier *= 1f + MartialBonus(___m_character, (Bonus)8); } } [HarmonyPatch(typeof(SEMan), "ModifyHealthRegen")] private static class MartialHealthPatch { private static void Postfix(Character ___m_character, ref float regenMultiplier) { regenMultiplier *= 1f + MartialBonus(___m_character, (Bonus)9); } } [HarmonyPatch(typeof(Player), "GetBodyArmor")] private static class MartialArmourPatch { private static void Postfix(Player __instance, ref float __result) { __result += MartialBonus((Character)(object)__instance, (Bonus)14); Progression val = MartialState((Character)(object)__instance); if (val != null) { Plugin instance = Instance; double num = Time.unscaledTime; __result += MartialCombat.ScarArmour(val, ((Character)__instance).GetHealthPercentage()); if (val.ClassId == "highlander") { __result += instance._martial.ResolveArmour(val, num); } } } } [HarmonyPatch(typeof(Character), "AddStaggerDamage")] private static class MartialStaggerPatch { private static void Prefix(Character __instance, ref float damage) { damage *= 1f - MartialBonus(__instance, (Bonus)7); Progression val = ActiveState(__instance, "monk"); if (val != null && Instance._martial.Unmovable(val, (double)Time.unscaledTime)) { damage = 0f; } Progression val2 = MartialState(__instance); if (val2 == null) { return; } Plugin instance = Instance; if (val2.ClassId == "highlander") { damage *= 1f - instance._martial.ResolveStagger(val2, (double)Time.unscaledTime); } else if (val2.ClassId == "breaker") { damage *= 1f - instance._martial.AnvilStagger(val2); if (instance._martial.Unmoved(val2) && !__instance.IsBoss()) { damage = 0f; } } } } [HarmonyPatch(typeof(SEMan), "ModifyAttackStaminaUsage")] private static class MonkAttackCostPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { if (!Fists(___m_character) && !WieldsPairedAxes(___m_character) && !WieldsGreatsword(___m_character) && !WieldsTwoHandedAxe(___m_character)) { return; } staminaUse *= 1f - MartialBonus(___m_character, (Bonus)12); Progression val = MartialState(___m_character); if (val == null) { return; } Plugin instance = Instance; double num = Time.unscaledTime; if (val.ClassId == "highlander") { Player val2 = (Player)(object)((___m_character is Player) ? ___m_character : null); if (val2 != null) { staminaUse *= 1f - instance._martial.RoomDiscount(val, instance.EnemiesNear(val2, 1.5f) == 0); goto IL_00bf; } } if (val.ClassId == "breaker") { staminaUse *= 1f - instance._martial.CrowdDiscount(val, instance.NearEnemies); } goto IL_00bf; IL_00bf: if ((Fists(___m_character) && instance._martial.Focused(val, num)) || instance._martial.Tireless(val, num)) { staminaUse = 0f; } } } [HarmonyPatch(typeof(SEMan), "ModifyBlockStaminaUsage")] private static class MonkBlockCostPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { if (Fists(___m_character)) { staminaUse *= 1f - MartialBonus(___m_character, (Bonus)15); } } } [HarmonyPatch(typeof(SEMan), "ModifyFallDamage")] private static class RogueFallPatch { private static void Postfix(Character ___m_character, ref float damage) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) Progression val = ActiveState(___m_character, "rogue"); if (val == null) { return; } float num = Instance._martial.Fall(val, (double)Time.unscaledTime, damage); if (!(num <= 0f)) { damage -= num; float fallStamina = MartialCombat.RogueTune(val).FallStamina; if (fallStamina > 0f) { ((Character)(Player)___m_character).AddStamina(fallStamina); } } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class BreakerResistPatch { private static void Prefix(Character __instance, HitData hit) { Plugin instance = Instance; if ((Object)(object)instance == (Object)null || !((Behaviour)instance).enabled || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || hit == null) { return; } Progression val = MartialState(__instance); if (val != null && !(val.ClassId != "breaker")) { float num = instance._martial.AnvilResistance(val); if (num > 0f) { hit.ApplyModifier(1f - num); } } } } [HarmonyPatch(typeof(Player), "OnDamaged")] private static class MartialWoundedPatch { private static void Postfix(Player __instance, HitData hit) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) Progression val = MartialState((Character)(object)__instance); if (val == null || ((Character)__instance).IsDead() || hit.GetTotalDamage() <= 0f || !EnemyHit((Character)(object)__instance, hit.GetAttacker())) { return; } Plugin instance = Instance; if (val.ClassId == "monk") { instance._martial.OnHurt(val, (double)Time.unscaledTime); } float num = instance._martial.OnWounded(val, (double)Time.unscaledTime, ((Character)__instance).GetHealthPercentage()); if (num <= 0f) { return; } ((Character)__instance).Heal(num, false); if (val.ClassId == "highlander") { instance.Notify("Last rites."); } else if (val.ClassId == "berserker" || val.ClassId == "breaker") { instance.Notify("Death refuses you."); } else if (!(val.ClassId != "rogue")) { RogueTuning val2 = MartialCombat.RogueTune(val); ((Character)__instance).AddStamina(val2.SurviveStamina); if (val2.SurviveBreaks) { instance._martial.BeginShroud((double)Time.unscaledTime, 4.0); instance.BreakContact(__instance, 20f); instance.Notify("Smoke and mirrors."); } } } } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] private static class MonkBlockPatch { private static void Prefix(HitData hit, out float __state) { __state = hit.GetTotalBlockableDamage(); } private static void Postfix(Humanoid __instance, HitData hit, Character attacker, bool __result, float __state) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown Progression val = ActiveState((Character)(object)__instance, "monk"); if (val == null || !Fists((Character)(object)__instance) || !__result || !EnemyHit((Character)(object)__instance, attacker) || !((Character)__instance).HaveStamina(0f) || ((Character)__instance).IsStaggering() || hit.GetTotalBlockableDamage() >= __state) { return; } Plugin instance = Instance; float num = instance._martial.OnBlock(val, (double)Time.unscaledTime); if (!(num <= 0f)) { ((Character)__instance).AddStamina(num); if (MartialCombat.MonkTune(val).ParryTurn) { instance.ShieldPulse((Player)__instance, 3f, 25f); } } } } [HarmonyPatch(typeof(TreeBase), "Damage")] private static class MonkTreeGatherPatch { private static void Prefix(TreeBase __instance, HitData hit) { MonkGather(hit, __instance.m_minToolTier); } } [HarmonyPatch(typeof(TreeLog), "Damage")] private static class MonkLogGatherPatch { private static void Prefix(TreeLog __instance, HitData hit) { MonkGather(hit, __instance.m_minToolTier); } } [HarmonyPatch(typeof(MineRock), "Damage")] private static class MonkRockGatherPatch { private static void Prefix(MineRock __instance, HitData hit) { MonkGather(hit, __instance.m_minToolTier); } } [HarmonyPatch(typeof(MineRock5), "Damage")] private static class MonkRock5GatherPatch { private static void Prefix(MineRock5 __instance, HitData hit) { MonkGather(hit, __instance.m_minToolTier); } } [HarmonyPatch(typeof(ZNet), "Awake")] private static class NetworkAwakePatch { private static void Postfix(ZNet __instance) { Instance?.ResetNetwork(__instance); } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class NetworkConnectPatch { private static void Postfix(ZNetPeer peer) { Instance?.RegisterPeer(peer); } } private sealed class DeathMarker { } [HarmonyPatch(typeof(Character), "OnDeath")] private static class DeathPatch { private static void Prefix(Character __instance, HitData ___m_lastHit) { try { Instance?.RewardDeath(__instance, ___m_lastHit); } catch (Exception ex) { Plugin? instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogError((object)("Kill reward failed: " + ex)); } } } } [HarmonyPatch(typeof(Player), "Save")] private static class SavePatch { private static void Prefix(Player __instance) { if ((Object)(object)Instance?._player == (Object)(object)__instance) { Instance.Persist(); } } } [HarmonyPatch(typeof(Player), "Load")] private static class LoadPatch { private static void Postfix(Player __instance) { if ((Object)(object)Instance?._player == (Object)(object)__instance) { Instance._player = null; Instance.EnsurePlayer(__instance); } } } [HarmonyPatch(typeof(Attack), "GetAttackStamina")] private static class AttackPatch { private static void Postfix(Humanoid ___m_character, ItemData ___m_weapon, ref float __result) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (__result > 0f && ___m_weapon != null && IsMelee(___m_weapon.m_shared.m_skillType)) { Progression val = ActiveState((Character)(object)___m_character); if (val != null) { __result *= Instance._combat.AttackCost(val, (double)Time.unscaledTime); } } } } [HarmonyPatch(typeof(SEMan), "ModifyBlockStaminaUsage")] private static class BlockPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { Progression val = ActiveState(___m_character); if (val != null && staminaUse > 0f) { staminaUse *= val.BlockStaminaMultiplier; } } } [HarmonyPatch(typeof(Player), "TakeInput")] private static class PlayerInputPatch { private static void Postfix(ref bool __result) { if (BlocksInput) { __result = false; } } } [HarmonyPatch(typeof(PlayerController), "TakeInput")] private static class ControllerInputPatch { private static void Postfix(bool look, ref bool __result) { if (look ? BlocksLook : BlocksInput) { __result = false; } } } [HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")] private static class CursorPatch { private static bool Prefix() { if ((Object)(object)Instance == (Object)null || (!Instance._open && !Instance._spellSelecting && !(Time.unscaledTime < Instance._blockInputUntil))) { return true; } ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); return false; } } [HarmonyPatch(typeof(SEMan), "ModifyAttack")] private static class RangerAttackPatch { private static void Postfix(Character ___m_character, SkillType skill, ref HitData hitData) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Progression val = ActiveState(___m_character, "ranger"); if (val != null && IsRangedWeapon(skill) && !(hitData.GetTotalDamage() <= 0f)) { ((DamageTypes)(ref hitData.m_damage)).Modify(Instance._ranger.ShotDamage(val)); } } } [HarmonyPatch(typeof(SEMan), "ModifyAttackStaminaUsage")] private static class RangerAttackCostPatch { private static void Postfix(Character ___m_character, ref float staminaUse) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) Progression val = ActiveState(___m_character, "ranger"); Character obj = ((___m_character is Humanoid) ? ___m_character : null); ItemData val2 = ((obj != null) ? ((Humanoid)obj).GetCurrentWeapon() : null); if (val != null && val2 != null && IsRangedWeapon(val2.m_shared.m_skillType) && !(staminaUse <= 0f)) { staminaUse *= Instance._ranger.AttackCost(val); staminaUse *= RangerCombat.EnduranceFactor(val, ___m_character.GetStaminaPercentage()); if (Instance._ranger.Snapshot(val, (double)Time.unscaledTime)) { staminaUse = 0f; } } } } [HarmonyPatch(typeof(Projectile), "Setup")] private static class RangerFlightPatch { private static void Prefix(Character owner, ref Vector3 velocity, HitData hitData) { //IL_0004: Unknown result type (might be due