Decompiled source of Oathbound v0.21.7

BepInEx/plugins/WarriorRpg/Warrior.Core.dll

Decompiled 2 hours ago
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
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