Decompiled source of WaysOfTheGods v3.6.0

WaysOfTheGods.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("WaysOfTheGods")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("3.6.0.0")]
[assembly: AssemblyInformationalVersion("3.6.0+07d160ffc1db6876141144213ba2f4e0476300ef")]
[assembly: AssemblyProduct("WaysOfTheGods")]
[assembly: AssemblyTitle("WaysOfTheGods")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.6.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ClassiDiValheim
{
	public class SpellDef
	{
		public string RawName;

		public int UnlockLevel;

		public float Cooldown;

		public float StaminaCost;

		public string IconItem;

		public Action<Player, int> CastAction;

		public Func<int, string> Describe;

		public float CastTime;

		public string Name
		{
			get
			{
				return Loc.T("spell." + Loc.Slug(RawName) + ".name", RawName);
			}
			set
			{
				RawName = value;
			}
		}
	}
	public static class Abilities
	{
		private enum AscendantElement
		{
			Fire,
			Frost,
			Lightning,
			Earth,
			Blood,
			Pierce,
			Poison,
			Spirit,
			Bone,
			Wild,
			Nature,
			Holy
		}

		private enum AscendantMode
		{
			Burst,
			Field,
			Ward,
			Drain,
			Companion
		}

		private sealed class AscendantPath
		{
			public string OmenName;

			public string OmenFlavor;

			public string OmenIcon;

			public AscendantMode OmenMode;

			public string MythicName;

			public string MythicFlavor;

			public string MythicIcon;

			public AscendantMode MythicMode;

			public AscendantElement Element;
		}

		private enum RangerTrapKind
		{
			Snare,
			Explosive,
			Venom
		}

		private static readonly Dictionary<string, float> CooldownEnd = new Dictionary<string, float>();

		public static bool DebugUnlockAll;

		private static readonly SpellDef MageFireballBase = new SpellDef
		{
			Name = "Fireball",
			UnlockLevel = 1,
			Cooldown = 6f,
			StaminaCost = 20f,
			IconItem = "StaffFireball",
			CastAction = CastFireball,
			Describe = (int lvl) => Loc.F("spell.fireball.desc", "Hurl a fireball ({0} damage)", AdjFireballDamage(lvl))
		};

		private static readonly SpellDef MageIceShardsBase = new SpellDef
		{
			Name = "Ice Shards",
			UnlockLevel = 1,
			Cooldown = 10f,
			StaminaCost = 30f,
			IconItem = "StaffIceShards",
			CastAction = CastIceShards,
			Describe = (int lvl) => Loc.F("spell.ice_shards.desc", "Fan of {0} freezing shards ({1} damage each)", IceShardCount(), AdjIceShardDamage(lvl))
		};

		private static readonly SpellDef MageLightningBoltBase = new SpellDef
		{
			Name = "Lightning Bolt",
			UnlockLevel = 1,
			Cooldown = 12f,
			StaminaCost = 35f,
			IconItem = "StaffLightning",
			CastAction = CastLightningBolt,
			Describe = (int lvl) => Loc.F("spell.lightning_bolt.desc", "Crackling projectile ({0} damage)", AdjLightningBoltDamage(lvl))
		};

		private static readonly SpellDef[] MageFireBaseOnly = new SpellDef[1] { MageFireballBase };

		private static readonly SpellDef[] MageFrostBaseOnly = new SpellDef[1] { MageIceShardsBase };

		private static readonly SpellDef[] MageLightningBaseOnly = new SpellDef[1] { MageLightningBoltBase };

		public static readonly SpellDef[] PyromancerSpells = new SpellDef[5]
		{
			MageFireballBase,
			new SpellDef
			{
				Name = "Ring of Fire",
				UnlockLevel = 10,
				Cooldown = 20f,
				StaminaCost = 45f,
				IconItem = "SurtlingCore",
				CastAction = CastRingOfFire,
				Describe = (int lvl) => Loc.F("spell.ring_of_fire.desc", "{0} fireballs in every direction ({1} damage each)", RingCount(), AdjRingFireDamage(lvl))
			},
			new SpellDef
			{
				Name = "Flame Wave",
				UnlockLevel = 20,
				Cooldown = 12f,
				StaminaCost = 30f,
				IconItem = "Torch",
				CastAction = CastFlameWave,
				Describe = (int lvl) => Loc.F("spell.flame_wave.desc", "A fan of 5 flames scorches everything ahead ({0} damage each)", AdjFlameWaveDamage(lvl))
			},
			new SpellDef
			{
				Name = "Pillar of Flame",
				UnlockLevel = 35,
				Cooldown = 18f,
				StaminaCost = 40f,
				IconItem = "GoblinTotem",
				CastAction = CastPillarOfFlame,
				Describe = (int lvl) => Loc.F("spell.pillar_of_flame.desc", "A meteor crashes on the nearest foe ahead ({0} damage", AdjPillarDamage(lvl)) + (TalentSystem.Has(LP, "pyr_twinpillar") ? ", strikes a second enemy)" : ")")
			},
			new SpellDef
			{
				Name = "Meteor Shower",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 80f,
				IconItem = "Obsidian",
				CastTime = 2.5f,
				CastAction = CastWrathOfTheGods,
				Describe = (int lvl) => Loc.F("spell.meteor_shower.desc", "{0} meteors rain in front of you ({1} damage each)", MeteorCount(), AdjMeteorDamage(lvl))
			}
		};

		public static readonly SpellDef[] FlameSummonerSpells = new SpellDef[5]
		{
			MageFireballBase,
			new SpellDef
			{
				Name = "Summon Fire Imp",
				UnlockLevel = 10,
				Cooldown = 12f,
				StaminaCost = 30f,
				IconItem = "TrophySurtling",
				CastAction = CastSummonFireImp,
				Describe = (int lvl) => Loc.F("spell.summon_fire_imp.desc", "A fire imp fights at your side (max {0})", FireImpCap())
			},
			new SpellDef
			{
				Name = "Burning Ground",
				UnlockLevel = 20,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "Coal",
				CastAction = CastBurningGround,
				Describe = (int lvl) => Loc.F("spell.burning_ground.desc", "Sets the ground ablaze ({0:0} m, {1:0} s, {2} fire/s)", BurningGroundRadius(), BurningGroundDuration(), AdjBurningTick(lvl)) + (TalentSystem.Has(LP, "smn_emberpact") ? " and mends your summons" : "")
			},
			new SpellDef
			{
				Name = "Summon Magma Elemental",
				UnlockLevel = 35,
				Cooldown = 45f,
				StaminaCost = 60f,
				IconItem = "Obsidian",
				CastAction = CastSummonMagmaElemental,
				Describe = (int lvl) => Loc.T("spell.summon_magma_elemental.desc", "An elite elemental of molten rock serves you (one at a time)")
			},
			new SpellDef
			{
				Name = "Legion of Cinders",
				UnlockLevel = 45,
				Cooldown = 90f,
				StaminaCost = 80f,
				IconItem = "SurtlingCore",
				CastTime = 2f,
				CastAction = CastLegionOfCinders,
				Describe = (int lvl) => Loc.F("spell.legion_of_cinders.desc", "{0} fire imps burst from the earth for {1:0} s", LegionCount(), LegionLifetime())
			}
		};

		public static readonly SpellDef[] CryomancerSpells = new SpellDef[5]
		{
			MageIceShardsBase,
			new SpellDef
			{
				Name = "Frost Nova",
				UnlockLevel = 10,
				Cooldown = 15f,
				StaminaCost = 30f,
				IconItem = "FreezeGland",
				CastAction = CastFrostNova,
				Describe = (int lvl) => Loc.F("spell.frost_nova.desc", "Explosion of frost around you ({0} damage, {1:0} m)", AdjFrostNovaDamage(lvl), FrostNovaRadius())
			},
			new SpellDef
			{
				Name = "Glacial Spike",
				UnlockLevel = 20,
				Cooldown = 8f,
				StaminaCost = 30f,
				IconItem = "Crystal",
				CastAction = CastGlacialSpike,
				Describe = (int lvl) => Loc.F("spell.glacial_spike.desc", "A massive spear of ice ({0} damage)", AdjGlacialSpikeDamage(lvl))
			},
			new SpellDef
			{
				Name = "Blizzard",
				UnlockLevel = 35,
				Cooldown = 25f,
				StaminaCost = 55f,
				IconItem = "FreezeGland",
				CastTime = 1.5f,
				CastAction = CastBlizzard,
				Describe = (int lvl) => Loc.F("spell.blizzard.desc", "A blizzard rages ahead for {0} s ({1} frost/s, {2:0} m)", 8, AdjBlizzardTick(lvl), BlizzardRadius())
			},
			new SpellDef
			{
				Name = "Absolute Zero",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 80f,
				IconItem = "TrophyDragonQueen",
				CastTime = 2.5f,
				CastAction = CastAbsoluteZero,
				Describe = (int lvl) => Loc.F("spell.absolute_zero.desc", "Winter itself erupts around you ({0} damage, {1:0} m)", AdjAbsoluteZeroDamage(lvl), 10f)
			}
		};

		public static readonly SpellDef[] FrostwardenSpells = new SpellDef[5]
		{
			MageIceShardsBase,
			new SpellDef
			{
				Name = "Rune Shield",
				UnlockLevel = 10,
				Cooldown = 60f,
				StaminaCost = 40f,
				IconItem = "StaffShield",
				CastAction = CastRuneShield,
				Describe = (int lvl) => Loc.F("spell.rune_shield.desc", "Protective dome ({0:0} m, {1:0} s): armors whoever is inside, dissolves projectiles and repels enemies", DomeRadius(), DomeDuration())
			},
			new SpellDef
			{
				Name = "Frost Armor",
				UnlockLevel = 20,
				Cooldown = 30f,
				StaminaCost = 30f,
				IconItem = "ArmorWolfChest",
				CastAction = CastFrostArmor,
				Describe = (int lvl) => Loc.F("spell.frost_armor.desc", "A shell of living ice armors you for {0:0} s", FrostArmorDuration()) + (TalentSystem.Has(LP, "fw_chillguard") ? " and bites attackers" : "")
			},
			new SpellDef
			{
				Name = "Winter's Grasp",
				UnlockLevel = 35,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "FreezeGland",
				CastAction = CastWintersGrasp,
				Describe = (int lvl) => Loc.F("spell.winter_s_grasp.desc", "Freezes the ground ahead ({0:0} m, {1:0} s, {2} frost/s)", GraspRadius(), 8f, AdjGraspTick(lvl))
			},
			new SpellDef
			{
				Name = "Fimbulwinter",
				UnlockLevel = 45,
				Cooldown = 90f,
				StaminaCost = 80f,
				IconItem = "TrophySGolem",
				CastTime = 2.5f,
				CastAction = CastFimbulwinter,
				Describe = (int lvl) => Loc.F("spell.fimbulwinter.desc", "The great winter: a vast dome ({0:0} m, 20 s) and a killing frost ({1} damage)", FimbulRadius(), AdjFimbulBlastDamage(lvl))
			}
		};

		public static readonly SpellDef[] StormcallerSpells = new SpellDef[5]
		{
			MageLightningBoltBase,
			new SpellDef
			{
				Name = "Chain Lightning",
				UnlockLevel = 10,
				Cooldown = 8f,
				StaminaCost = 30f,
				IconItem = "Thunderstone",
				CastAction = CastChainLightning,
				Describe = (int lvl) => Loc.F("spell.chain_lightning.desc", "A bolt that leaps to {0} enemies ({1} damage, fading each jump)", 1 + ChainJumps(), AdjChainDamage(lvl))
			},
			new SpellDef
			{
				Name = "Static Field",
				UnlockLevel = 20,
				Cooldown = 18f,
				StaminaCost = 40f,
				IconItem = "Chain",
				CastAction = CastStaticField,
				Describe = (int lvl) => Loc.F("spell.static_field.desc", "Electrifies the ground ahead ({0:0} m, {1:0} s, {2} lightning/s)", FieldRadius(), FieldDuration(), AdjFieldTick(lvl))
			},
			new SpellDef
			{
				Name = "Lightning Storm",
				UnlockLevel = 35,
				Cooldown = 30f,
				StaminaCost = 60f,
				IconItem = "TrophyEikthyr",
				CastTime = 1.5f,
				CastAction = CastLightningStorm,
				Describe = (int lvl) => Loc.F("spell.lightning_storm.desc", "{0} bolts strike nearby enemies ({1} damage each)", StormBolts(), AdjStormBoltDamage(lvl))
			},
			new SpellDef
			{
				Name = "Wrath of Thor",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 80f,
				IconItem = "SledgeStagbreaker",
				CastTime = 2.5f,
				CastAction = CastWrathOfThor,
				Describe = (int lvl) => Loc.F("spell.wrath_of_thor.desc", "{0} godly bolts hammer everything around you ({1} damage each)", 12, AdjThorBoltDamage(lvl))
			}
		};

		public static readonly SpellDef[] TempestSpells = new SpellDef[5]
		{
			MageLightningBoltBase,
			new SpellDef
			{
				Name = "Blink",
				UnlockLevel = 10,
				Cooldown = 10f,
				StaminaCost = 25f,
				IconItem = "Feathers",
				CastAction = CastBlink,
				Describe = (int lvl) => Loc.F("spell.blink.desc", "You become lightning: flash {0:0} m forward", BlinkDistance()) + (TalentSystem.Has(LP, "tm_slipstream") ? " and surge with power" : "")
			},
			new SpellDef
			{
				Name = "Storm Shroud",
				UnlockLevel = 20,
				Cooldown = 25f,
				StaminaCost = 30f,
				IconItem = "Wisp",
				CastAction = CastStormShroud,
				Describe = (int lvl) => Loc.F("spell.storm_shroud.desc", "Crackling static wraps you for {0:0} s: whoever strikes you gets zapped", ShroudDuration())
			},
			new SpellDef
			{
				Name = "Ball Lightning",
				UnlockLevel = 35,
				Cooldown = 20f,
				StaminaCost = 45f,
				IconItem = "Thunderstone",
				CastAction = CastBallLightning,
				Describe = (int lvl) => Loc.F("spell.ball_lightning.desc", "A roaming orb of lightning ({0:0} s, {1} lightning per zap)", BallDuration(), AdjBallTick(lvl))
			},
			new SpellDef
			{
				Name = "Eye of the Storm",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 80f,
				IconItem = "TrophyEikthyr",
				CastTime = 2f,
				CastAction = CastEyeOfTheStorm,
				Describe = (int lvl) => Loc.F("spell.eye_of_the_storm.desc", "The storm follows YOU for {0:0} s, smiting foes within {1:0} m ({2} damage)", 10f, EyeRadius(), AdjEyeBoltDamage(lvl))
			}
		};

		private static readonly SpellDef BersCrushingBlow = new SpellDef
		{
			Name = "Crushing Blow",
			UnlockLevel = 1,
			Cooldown = 5f,
			StaminaCost = 15f,
			IconItem = "MaceBronze",
			CastAction = CastCrushingBlow,
			Describe = (int lvl) => Loc.F("spell.crushing_blow.desc", "A heavy blow smashes the ground ahead ({0} blunt, {1:0.#} m) — enemies stagger", AdjCrushingBlowDamage(lvl), CrushingBlowRadius())
		};

		private static readonly SpellDef BersCleave = new SpellDef
		{
			Name = "Cleave",
			UnlockLevel = 1,
			Cooldown = 5f,
			StaminaCost = 15f,
			IconItem = "AxeIron",
			CastAction = CastCleave,
			Describe = (int lvl) => Loc.F("spell.cleave.desc", "A wide arc cuts everything in front ({0} slash, {1:0.#} m)", AdjCleaveDamage(lvl), CleaveRadius()) + ((TalentSystem.Rank(LP, "re_bleed") > 0) ? " and makes them bleed" : "")
		};

		private static readonly SpellDef BersSpearThrow = new SpellDef
		{
			Name = "Spear Throw",
			UnlockLevel = 1,
			Cooldown = 6f,
			StaminaCost = 15f,
			IconItem = "SpearBronze",
			CastAction = CastSpearThrow,
			Describe = (int lvl) => Loc.F("spell.spear_throw.desc", "Hurl an ancient spear ({0} pierce)", AdjSpearThrowDamage(lvl))
		};

		private static readonly SpellDef[] BersCrushingBaseOnly = new SpellDef[1] { BersCrushingBlow };

		private static readonly SpellDef[] BersRendingBaseOnly = new SpellDef[1] { BersCleave };

		private static readonly SpellDef[] BersHuntingBaseOnly = new SpellDef[1] { BersSpearThrow };

		public static readonly SpellDef[] JuggernautSpells = new SpellDef[5]
		{
			BersCrushingBlow,
			new SpellDef
			{
				Name = "Iron Skin",
				UnlockLevel = 10,
				Cooldown = 60f,
				StaminaCost = 30f,
				IconItem = "ArmorIronChest",
				CastAction = CastIronSkin,
				Describe = (int lvl) => Loc.F("spell.iron_skin.desc", "Your skin turns to iron: massive defense for {0:0} s", IronSkinDuration())
			},
			new SpellDef
			{
				Name = "War Cry",
				UnlockLevel = 20,
				Cooldown = 10f,
				StaminaCost = 20f,
				IconItem = "TrophyBoar",
				CastAction = CastWarCry,
				Describe = (int lvl) => Loc.F("spell.war_cry.desc", "Repels and damages nearby enemies ({0} blunt, {1:0.#} m)", AdjWarCryDamage(lvl), WarCryRadius())
			},
			new SpellDef
			{
				Name = "Berserker Fury",
				UnlockLevel = 35,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "TrophyWolf",
				CastAction = CastFury,
				Describe = (int lvl) => Loc.F("spell.berserker_fury.desc", "+{0}% damage and nearly free attacks for {1:0} s", FuryPercent(), FuryDuration())
			},
			new SpellDef
			{
				Name = "Titanic Slam",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 60f,
				IconItem = "SledgeDemolisher",
				CastAction = CastTitanicSlam,
				Describe = (int lvl) => Loc.F("spell.titanic_slam.desc", "Leap skyward and crash down ({0} blunt, {1:0.#} m)", AdjSlamDamage(lvl), SlamRadius())
			}
		};

		public static readonly SpellDef[] EarthshakerSpells = new SpellDef[5]
		{
			BersCrushingBlow,
			new SpellDef
			{
				Name = "Seismic Blow",
				UnlockLevel = 10,
				Cooldown = 12f,
				StaminaCost = 30f,
				IconItem = "SledgeIron",
				CastAction = CastSeismicBlow,
				Describe = (int lvl) => Loc.F("spell.seismic_blow.desc", "Make the earth tremble ({0} blunt, {1:0.#} m)", AdjSeismicDamage(lvl), SeismicRadius())
			},
			new SpellDef
			{
				Name = "Fault Line",
				UnlockLevel = 20,
				Cooldown = 15f,
				StaminaCost = 35f,
				IconItem = "SledgeStagbreaker",
				CastAction = CastFaultLine,
				Describe = (int lvl) => Loc.F("spell.fault_line.desc", "The ground erupts in a line ahead ({0} blunt, {1:0} m) — enemies stagger", AdjFaultLineDamage(lvl), FaultLineLength())
			},
			new SpellDef
			{
				Name = "War Cry",
				UnlockLevel = 35,
				Cooldown = 10f,
				StaminaCost = 20f,
				IconItem = "TrophyBoar",
				CastAction = CastWarCry,
				Describe = (int lvl) => Loc.F("spell.war_cry.desc", "Repels and damages nearby enemies ({0} blunt, {1:0.#} m)", AdjWarCryDamage(lvl), WarCryRadius())
			},
			new SpellDef
			{
				Name = "Cataclysm",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 60f,
				IconItem = "SledgeDemolisher",
				CastAction = CastCataclysm,
				Describe = (int lvl) => Loc.F("spell.cataclysm.desc", "Leap and shatter the earth ({0} blunt, {1:0.#} m) — a second wave follows", AdjCataclysmDamage(lvl), SlamRadius())
			}
		};

		public static readonly SpellDef[] ReaverSpells = new SpellDef[5]
		{
			BersCleave,
			new SpellDef
			{
				Name = "Whirlwind",
				UnlockLevel = 10,
				Cooldown = 25f,
				StaminaCost = 45f,
				IconItem = "AtgeirBlackmetal",
				CastAction = CastWhirlwind,
				Describe = (int lvl) => Loc.F("spell.whirlwind.desc", "Spinning blades for {0:0.#} s ({1} slash per hit, {2:0.#} m)", (float)WhirlTicks() * 0.5f, AdjWhirlDamage(lvl), WhirlRadius())
			},
			new SpellDef
			{
				Name = "Rend",
				UnlockLevel = 20,
				Cooldown = 10f,
				StaminaCost = 25f,
				IconItem = "KnifeBlackMetal",
				CastAction = CastRupture,
				Describe = (int lvl) => Loc.F("spell.rend.desc", "A savage cut ({0} slash) that bleeds for {1:0} s", AdjRuptureDamage(lvl), RuptureBleedDuration())
			},
			new SpellDef
			{
				Name = "Iron Skin",
				UnlockLevel = 35,
				Cooldown = 60f,
				StaminaCost = 30f,
				IconItem = "ArmorIronChest",
				CastAction = CastIronSkin,
				Describe = (int lvl) => Loc.F("spell.iron_skin.desc", "Your skin turns to iron: massive defense for {0:0} s", IronSkinDuration())
			},
			new SpellDef
			{
				Name = "Bloodbath",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 60f,
				IconItem = "AxeBlackMetal",
				CastAction = CastBloodbath,
				Describe = (int lvl) => Loc.F("spell.bloodbath.desc", "A storm of blades for {0:0.#} s ({1} slash per hit, {2:0.#} m) — heals you per enemy struck", (float)BloodbathTicks() * 0.5f, AdjBloodbathDamage(lvl), BloodbathRadius())
			}
		};

		public static readonly SpellDef[] RavagerSpells = new SpellDef[5]
		{
			BersCleave,
			new SpellDef
			{
				Name = "Charge",
				UnlockLevel = 10,
				Cooldown = 8f,
				StaminaCost = 20f,
				IconItem = "AxeIron",
				CastAction = CastCharge,
				Describe = (int lvl) => Loc.F("spell.charge.desc", "Forward dash that tramples enemies ({0} slash)", AdjChargeDamage(lvl))
			},
			new SpellDef
			{
				Name = "Execute",
				UnlockLevel = 20,
				Cooldown = 10f,
				StaminaCost = 25f,
				IconItem = "AxeBlackMetal",
				CastAction = CastExecute,
				Describe = (int lvl) => Loc.F("spell.execute.desc", "A brutal strike on the foe ahead ({0} slash, up to +{1}% vs wounded enemies)", AdjExecuteDamage(lvl), ExecuteBonusPercent())
			},
			new SpellDef
			{
				Name = "Berserker Fury",
				UnlockLevel = 35,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "TrophyWolf",
				CastAction = CastFury,
				Describe = (int lvl) => Loc.F("spell.berserker_fury.desc", "+{0}% damage and nearly free attacks for {1:0} s", FuryPercent(), FuryDuration())
			},
			new SpellDef
			{
				Name = "Rampage",
				UnlockLevel = 45,
				Cooldown = 45f,
				StaminaCost = 55f,
				IconItem = "SwordIron",
				CastAction = CastRampage,
				Describe = (int lvl) => Loc.F("spell.rampage.desc", "A frenzy of {0} strikes on the enemy ahead ({1} slash each)", RampageHits(), AdjRampageDamage(lvl))
			}
		};

		public static readonly SpellDef[] LancerSpells = new SpellDef[5]
		{
			BersSpearThrow,
			new SpellDef
			{
				Name = "Charge",
				UnlockLevel = 10,
				Cooldown = 8f,
				StaminaCost = 20f,
				IconItem = "AxeIron",
				CastAction = CastCharge,
				Describe = (int lvl) => Loc.F("spell.charge.desc", "Lance forward, trampling enemies ({0} pierce)", AdjChargeDamage(lvl))
			},
			new SpellDef
			{
				Name = "Spear Barrage",
				UnlockLevel = 20,
				Cooldown = 8f,
				StaminaCost = 25f,
				IconItem = "SpearChitin",
				CastAction = CastSpearBarrage,
				Describe = (int lvl) => Loc.F("spell.spear_barrage.desc", "Hurl a fan of {0} spears ({1} pierce each)", SpearVolleyCount(), AdjSpearVolleyDamage(lvl))
			},
			new SpellDef
			{
				Name = "Impale",
				UnlockLevel = 35,
				Cooldown = 12f,
				StaminaCost = 35f,
				IconItem = "SpearChitin",
				CastAction = CastImpale,
				Describe = (int lvl) => Loc.F("spell.impale.desc", "A heavy spear runs through the foes ahead ({0} pierce)", AdjImpaleDamage(lvl)) + (TalentSystem.Has(LP, "la_impalepull") ? " and drags them to you" : "")
			},
			new SpellDef
			{
				Name = "Spear Storm",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 80f,
				IconItem = "SpearBronze",
				CastTime = 0f,
				CastAction = CastSpearStorm,
				Describe = (int lvl) => Loc.F("spell.spear_storm.desc", "{0} spears rain from the sky ({1} pierce each, {2:0.#} m)", SpearStormCount(), AdjSpearStormDamage(lvl), SpearStormRadius())
			}
		};

		public static readonly SpellDef[] WarhoundSpells = new SpellDef[5]
		{
			BersSpearThrow,
			new SpellDef
			{
				Name = "Pounce",
				UnlockLevel = 10,
				Cooldown = 8f,
				StaminaCost = 20f,
				IconItem = "SpearChitin",
				CastAction = CastPounce,
				Describe = (int lvl) => Loc.F("spell.pounce.desc", "Leap onto the nearest foe within {0:0} m ({1} pierce)", PounceRange(), AdjPounceDamage(lvl))
			},
			new SpellDef
			{
				Name = "Rapid Throw",
				UnlockLevel = 20,
				Cooldown = 10f,
				StaminaCost = 25f,
				IconItem = "SpearBronze",
				CastAction = CastRapidThrow,
				Describe = (int lvl) => Loc.F("spell.rapid_throw.desc", "Hurl {0} spears in quick succession ({1} pierce each)", RapidThrowCount(), AdjRapidThrowDamage(lvl))
			},
			new SpellDef
			{
				Name = "Berserker Fury",
				UnlockLevel = 35,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "TrophyWolf",
				CastAction = CastFury,
				Describe = (int lvl) => Loc.F("spell.berserker_fury.desc", "+{0}% damage and nearly free attacks for {1:0} s", FuryPercent(), FuryDuration())
			},
			new SpellDef
			{
				Name = "Wild Hunt",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 50f,
				IconItem = "TrophyWolf",
				CastAction = CastWildHunt,
				Describe = (int lvl) => Loc.F("spell.wild_hunt.desc", "The hunt takes you: +{0}% attack, faster and tireless for {1:0} s", WildHuntPercent(), WildHuntDuration())
			}
		};

		public static readonly SpellDef[] NecromancerSpells = new SpellDef[8]
		{
			new SpellDef
			{
				Name = "Life Drain",
				UnlockLevel = 10,
				Cooldown = 8f,
				StaminaCost = 20f,
				IconItem = "Bloodbag",
				CastAction = CastLifeDrain,
				Describe = (int lvl) => Loc.F("spell.life_drain.desc", "Drain the life of nearby enemies ({0} damage, {1} HP healed per enemy hit)", AdjDrainDamage(lvl), AdjDrainHeal(lvl))
			},
			new SpellDef
			{
				Name = "Summon Skeleton",
				UnlockLevel = 20,
				Cooldown = 10f,
				StaminaCost = 30f,
				IconItem = "TrophySkeleton",
				CastAction = CastSummonSkeleton,
				Describe = (int lvl) => Loc.F("spell.summon_skeleton.desc", "Raise a skeleton that fights for you (max {0})", MaxSkeletons(lvl))
			},
			new SpellDef
			{
				Name = "Ooze Bomb",
				UnlockLevel = 30,
				Cooldown = 8f,
				StaminaCost = 25f,
				IconItem = "Ooze",
				CastAction = CastOozeBomb,
				Describe = (int lvl) => Loc.F("spell.ooze_bomb.desc", "Throw a bomb that bursts into a poison cloud ({0} poison damage)", AdjOozeDamage(lvl))
			},
			new SpellDef
			{
				Name = "Toxic Cloud",
				UnlockLevel = 40,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "Guck",
				CastTime = 1.5f,
				CastAction = CastToxicCloud,
				Describe = (int lvl) => Loc.F("spell.toxic_cloud.desc", "Bonemass miasma in front of you: {0} waves of poison ({1} damage each, {2:0} m)", ToxicWaves(), AdjToxicTick(lvl), ToxicRadius())
			},
			new SpellDef
			{
				Name = "Spectral Wave",
				UnlockLevel = 50,
				Cooldown = 18f,
				StaminaCost = 45f,
				IconItem = "Entrails",
				CastAction = CastSpectralWave,
				Describe = (int lvl) => Loc.F("spell.spectral_wave.desc", "Wave of spirits that rends and repels ({0} damage, 8 m)", AdjSpectralDamage(lvl))
			},
			new SpellDef
			{
				Name = "Bone Armor",
				UnlockLevel = 60,
				Cooldown = 60f,
				StaminaCost = 30f,
				IconItem = "BoneFragments",
				CastAction = CastBoneArmor,
				Describe = (int lvl) => Loc.F("spell.bone_armor.desc", "Ancient bones armor you for {0:0} seconds", BoneArmorDuration())
			},
			new SpellDef
			{
				Name = "Putrid Rain",
				UnlockLevel = 70,
				Cooldown = 30f,
				StaminaCost = 60f,
				IconItem = "BombOoze",
				CastTime = 2f,
				CastAction = CastPutridRain,
				Describe = (int lvl) => Loc.F("spell.putrid_rain.desc", "{0} ooze bombs rain down in front of you ({1} poison damage each)", PutridBombs(), AdjPutridDamage(lvl))
			},
			new SpellDef
			{
				Name = "Army of the Dead",
				UnlockLevel = 80,
				Cooldown = 90f,
				StaminaCost = 80f,
				IconItem = "TrophyDraugrElite",
				CastTime = 2.5f,
				CastAction = CastArmyOfTheDead,
				Describe = (int lvl) => Loc.F("spell.army_of_the_dead.desc", "{0} skeletons rise for {1:0} s plus a spectral blast ({2} damage, 10 m)", ArmyCount(), ArmyLifetime, AdjSpectralDamage(lvl))
			}
		};

		public static readonly SpellDef[] OverlordSpells = new SpellDef[8]
		{
			new SpellDef
			{
				Name = "Life Drain",
				UnlockLevel = 10,
				Cooldown = 8f,
				StaminaCost = 20f,
				IconItem = "TrophySkeleton",
				CastAction = CastLifeDrain,
				Describe = (int lvl) => Loc.F("spell.life_drain.desc", "Drain the life of nearby enemies ({0} damage, {1} HP healed per enemy hit)", AdjDrainDamage(lvl), AdjDrainHeal(lvl))
			},
			new SpellDef
			{
				Name = "Summon Revenant",
				UnlockLevel = 20,
				Cooldown = 12f,
				StaminaCost = 35f,
				IconItem = "TrophySkeletonPoison",
				CastAction = CastSummonRevenant,
				Describe = (int lvl) => Loc.F("spell.summon_revenant.desc", "Raise an ELITE skeleton with fearsome strength (max {0} minions)", MaxSkeletons(lvl))
			},
			new SpellDef
			{
				Name = "Ooze Bomb",
				UnlockLevel = 30,
				Cooldown = 8f,
				StaminaCost = 25f,
				IconItem = "Ooze",
				CastAction = CastOozeBomb,
				Describe = (int lvl) => Loc.F("spell.ooze_bomb.desc", "Throw a bomb that bursts into a poison cloud ({0} poison damage)", AdjOozeDamage(lvl))
			},
			new SpellDef
			{
				Name = "Toxic Cloud",
				UnlockLevel = 40,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "Guck",
				CastTime = 1.5f,
				CastAction = CastToxicCloud,
				Describe = (int lvl) => Loc.F("spell.toxic_cloud.desc", "Bonemass miasma in front of you: {0} waves of poison ({1} damage each, {2:0} m)", ToxicWaves(), AdjToxicTick(lvl), ToxicRadius())
			},
			new SpellDef
			{
				Name = "Spectral Wave",
				UnlockLevel = 50,
				Cooldown = 15f,
				StaminaCost = 35f,
				IconItem = "TrophyWraith",
				CastAction = CastSpectralWave,
				Describe = (int lvl) => Loc.F("spell.spectral_wave.desc", "Wave of spirits that rends and repels ({0} damage, 8 m)", AdjSpectralDamage(lvl))
			},
			new SpellDef
			{
				Name = "Bone Pact",
				UnlockLevel = 60,
				Cooldown = 60f,
				StaminaCost = 30f,
				IconItem = "BoneFragments",
				CastAction = CastBonePact,
				Describe = (int lvl) => Loc.F("spell.bone_pact.desc", "Ancient bones armor you for {0:0} s while your minions are healed and enraged (+{1}% damage for {2:0} s)", BoneArmorDuration(), PactBonusPercent(), PactDuration())
			},
			new SpellDef
			{
				Name = "Putrid Rain",
				UnlockLevel = 70,
				Cooldown = 30f,
				StaminaCost = 60f,
				IconItem = "BombOoze",
				CastTime = 2f,
				CastAction = CastPutridRain,
				Describe = (int lvl) => Loc.F("spell.putrid_rain.desc", "{0} ooze bombs rain down in front of you ({1} poison damage each)", PutridBombs(), AdjPutridDamage(lvl))
			},
			new SpellDef
			{
				Name = "Endless Legion",
				UnlockLevel = 80,
				Cooldown = 90f,
				StaminaCost = 80f,
				IconItem = "TrophyDraugrElite",
				CastTime = 2.5f,
				CastAction = CastArmyOfTheDead,
				Describe = (int lvl) => Loc.F("spell.endless_legion.desc", "{0} skeletons rise for {1:0} s plus a spectral blast ({2} damage, 10 m)", ArmyCount(), ArmyLifetime, AdjSpectralDamage(lvl))
			}
		};

		private static readonly SpellDef NecroOozeBomb = new SpellDef
		{
			Name = "Ooze Bomb",
			UnlockLevel = 1,
			Cooldown = 8f,
			StaminaCost = 25f,
			IconItem = "Ooze",
			CastAction = CastOozeBomb,
			Describe = (int lvl) => Loc.F("spell.ooze_bomb.desc", "Throw a bomb that bursts into a poison cloud ({0} poison damage)", AdjOozeDamage(lvl))
		};

		private static readonly SpellDef NecroLifeDrain = new SpellDef
		{
			Name = "Life Drain",
			UnlockLevel = 1,
			Cooldown = 8f,
			StaminaCost = 20f,
			IconItem = "Bloodbag",
			CastAction = CastLifeDrain,
			Describe = (int lvl) => Loc.F("spell.life_drain.desc", "Drain the life of nearby enemies ({0} spirit, {1} HP per enemy)", AdjDrainDamage(lvl), AdjDrainHeal(lvl))
		};

		private static readonly SpellDef NecroSummonSkeleton = new SpellDef
		{
			Name = "Summon Skeleton",
			UnlockLevel = 1,
			Cooldown = 10f,
			StaminaCost = 30f,
			IconItem = "TrophySkeleton",
			CastAction = CastSummonSkeleton,
			Describe = (int lvl) => Loc.F("spell.summon_skeleton.desc", "Raise a skeleton that fights for you (max {0})", MaxSkeletons(lvl))
		};

		private static readonly SpellDef[] NecroPlagueBaseOnly = new SpellDef[1] { NecroOozeBomb };

		private static readonly SpellDef[] NecroSpiritBaseOnly = new SpellDef[1] { NecroLifeDrain };

		private static readonly SpellDef[] NecroBoneBaseOnly = new SpellDef[1] { NecroSummonSkeleton };

		public static readonly SpellDef[] PestilentSpells = new SpellDef[5]
		{
			NecroOozeBomb,
			new SpellDef
			{
				Name = "Toxic Cloud",
				UnlockLevel = 10,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "Guck",
				CastAction = CastToxicCloud,
				Describe = (int lvl) => Loc.F("spell.toxic_cloud.desc", "Bonemass miasma: {0} waves of poison ({1} each, {2:0} m)", ToxicWaves(), AdjToxicTick(lvl), ToxicRadius())
			},
			new SpellDef
			{
				Name = "Putrid Rain",
				UnlockLevel = 20,
				Cooldown = 24f,
				StaminaCost = 55f,
				IconItem = "BombOoze",
				CastTime = 1.5f,
				CastAction = CastPutridRain,
				Describe = (int lvl) => Loc.F("spell.putrid_rain.desc", "{0} ooze bombs rain down ({1} poison each)", PutridBombs(), AdjPutridDamage(lvl))
			},
			new SpellDef
			{
				Name = "Plague Nova",
				UnlockLevel = 35,
				Cooldown = 14f,
				StaminaCost = 40f,
				IconItem = "Guck",
				CastAction = CastPlagueNova,
				Describe = (int lvl) => Loc.F("spell.plague_nova.desc", "A burst of toxin around you ({0} poison, {1:0} m)", AdjPlagueNovaDamage(lvl), PlagueNovaRadius())
			},
			new SpellDef
			{
				Name = "Pandemic",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 80f,
				IconItem = "TrophyBonemass",
				CastAction = CastPandemic,
				Describe = (int lvl) => Loc.F("spell.pandemic.desc", "A great festering field ({0:0} m, {1:0} s, {2} poison/s)", PandemicRadius(), PandemicDuration(), AdjPandemicTick(lvl))
			}
		};

		public static readonly SpellDef[] BlightcallerSpells = new SpellDef[5]
		{
			NecroOozeBomb,
			new SpellDef
			{
				Name = "Plague Bolt",
				UnlockLevel = 10,
				Cooldown = 6f,
				StaminaCost = 20f,
				IconItem = "Guck",
				CastAction = CastPlagueBolt,
				Describe = (int lvl) => Loc.F("spell.plague_bolt.desc", "A fast bolt of venom ({0} poison), piercing {1} enemies", AdjPlagueBoltDamage(lvl), PlagueBoltPierce())
			},
			new SpellDef
			{
				Name = "Toxic Cloud",
				UnlockLevel = 20,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "Guck",
				CastAction = CastToxicCloud,
				Describe = (int lvl) => Loc.F("spell.toxic_cloud.desc", "Bonemass miasma: {0} waves of poison ({1} each, {2:0} m)", ToxicWaves(), AdjToxicTick(lvl), ToxicRadius())
			},
			new SpellDef
			{
				Name = "Corrode",
				UnlockLevel = 35,
				Cooldown = 10f,
				StaminaCost = 30f,
				IconItem = "Entrails",
				CastAction = CastCorrode,
				Describe = (int lvl) => Loc.F("spell.corrode.desc", "Rot the foe ahead: {0} poison over {1:0} s", AdjCorrodeDamage(lvl), CorrodeDuration()) + (TalentSystem.Has(LP, "bli_notable") ? ", spreading to a nearby enemy" : "")
			},
			new SpellDef
			{
				Name = "Putrid Rain",
				UnlockLevel = 45,
				Cooldown = 30f,
				StaminaCost = 60f,
				IconItem = "BombOoze",
				CastTime = 1.5f,
				CastAction = CastPutridRain,
				Describe = (int lvl) => Loc.F("spell.putrid_rain.desc", "{0} ooze bombs rain down ({1} poison each)", PutridBombs(), AdjPutridDamage(lvl))
			}
		};

		public static readonly SpellDef[] ReaperSpells = new SpellDef[5]
		{
			NecroLifeDrain,
			new SpellDef
			{
				Name = "Spectral Wave",
				UnlockLevel = 10,
				Cooldown = 18f,
				StaminaCost = 45f,
				IconItem = "Entrails",
				CastAction = CastSpectralWave,
				Describe = (int lvl) => Loc.F("spell.spectral_wave.desc", "Wave of spirits that rends and repels ({0} spirit, 8 m)", AdjSpectralDamage(lvl))
			},
			new SpellDef
			{
				Name = "Soul Rip",
				UnlockLevel = 20,
				Cooldown = 7f,
				StaminaCost = 20f,
				IconItem = "TrophyWraith",
				CastAction = CastSoulRip,
				Describe = (int lvl) => Loc.F("spell.soul_rip.desc", "A spectral lance ({0} spirit) that heals you {1} HP", AdjSoulRipDamage(lvl), SoulRipHeal(lvl))
			},
			new SpellDef
			{
				Name = "Bone Armor",
				UnlockLevel = 35,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "BoneFragments",
				CastAction = CastBoneArmor,
				Describe = (int lvl) => Loc.F("spell.bone_armor.desc", "Ancient bones armor you for {0:0} s", BoneArmorDuration())
			},
			new SpellDef
			{
				Name = "Death Coil",
				UnlockLevel = 45,
				Cooldown = 45f,
				StaminaCost = 60f,
				IconItem = "TrophyDraugr",
				CastAction = CastDeathCoil,
				Describe = (int lvl) => Loc.F("spell.death_coil.desc", "A wave of death ({0} spirit, {1:0} m) that heals you", AdjDeathCoilDamage(lvl), DeathCoilRadius())
			}
		};

		public static readonly SpellDef[] BansheeSpells = new SpellDef[5]
		{
			NecroLifeDrain,
			new SpellDef
			{
				Name = "Spectral Wave",
				UnlockLevel = 10,
				Cooldown = 18f,
				StaminaCost = 45f,
				IconItem = "Entrails",
				CastAction = CastSpectralWave,
				Describe = (int lvl) => Loc.F("spell.spectral_wave.desc", "Wave of spirits that rends and repels ({0} spirit, 8 m)", AdjSpectralDamage(lvl))
			},
			new SpellDef
			{
				Name = "Wail",
				UnlockLevel = 20,
				Cooldown = 12f,
				StaminaCost = 35f,
				IconItem = "TrophyDraugr",
				CastAction = CastWail,
				Describe = (int lvl) => Loc.F("spell.wail.desc", "A ghastly scream ({0} spirit, {1:0} m) that hurls foes back", AdjWailDamage(lvl), WailRadius())
			},
			new SpellDef
			{
				Name = "Spirit Nova",
				UnlockLevel = 35,
				Cooldown = 14f,
				StaminaCost = 40f,
				IconItem = "TrophyWraith",
				CastAction = CastSpiritNova,
				Describe = (int lvl) => Loc.F("spell.spirit_nova.desc", "A burst of spirits around you ({0} spirit, {1:0} m)", AdjSpiritNovaDamage(lvl), SpiritNovaRadius())
			},
			new SpellDef
			{
				Name = "Spectral Storm",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 80f,
				IconItem = "TrophyDraugrElite",
				CastAction = CastSpectralStorm,
				Describe = (int lvl) => Loc.F("spell.spectral_storm.desc", "{0} vengeful spirits rain down ({1} spirit each, {2:0} m)", SpectralStormCount(), AdjSpectralStormDamage(lvl), SpectralStormRadius())
			}
		};

		public static readonly SpellDef[] BonelordSpells = new SpellDef[5]
		{
			NecroSummonSkeleton,
			new SpellDef
			{
				Name = "Bone Armor",
				UnlockLevel = 10,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "BoneFragments",
				CastAction = CastBoneArmor,
				Describe = (int lvl) => Loc.F("spell.bone_armor.desc", "Ancient bones armor you for {0:0} s", BoneArmorDuration())
			},
			new SpellDef
			{
				Name = "Raise Horde",
				UnlockLevel = 20,
				Cooldown = 18f,
				StaminaCost = 45f,
				IconItem = "TrophySkeletonPoison",
				CastTime = 1f,
				CastAction = CastRaiseHorde,
				Describe = (int lvl) => Loc.F("spell.raise_horde.desc", "Instantly raise {0} skeletons (up to max {1})", RaiseHordeCount(), MaxSkeletons(lvl))
			},
			new SpellDef
			{
				Name = "Army of the Dead",
				UnlockLevel = 35,
				Cooldown = 90f,
				StaminaCost = 80f,
				IconItem = "TrophyDraugrElite",
				CastTime = 2.5f,
				CastAction = CastArmyOfTheDead,
				Describe = (int lvl) => Loc.F("spell.army_of_the_dead.desc", "{0} skeletons rise for {1:0} s plus a spectral blast ({2} damage, 10 m)", ArmyCount(), ArmyLifetime, AdjSpectralDamage(lvl))
			},
			new SpellDef
			{
				Name = "Bone Storm",
				UnlockLevel = 45,
				Cooldown = 40f,
				StaminaCost = 70f,
				IconItem = "TrophyDraugrElite",
				CastTime = 1f,
				CastAction = CastBoneStorm,
				Describe = (int lvl) => Loc.F("spell.bone_storm.desc", "A whirling storm of bone shards around you ({0} waves, {1} damage each, {2:0} m)", BoneStormWaves(), AdjBoneStormDamage(lvl), BoneStormRadius())
			}
		};

		public static readonly SpellDef[] DeathknightSpells = new SpellDef[5]
		{
			NecroSummonSkeleton,
			new SpellDef
			{
				Name = "Summon Revenant",
				UnlockLevel = 10,
				Cooldown = 12f,
				StaminaCost = 35f,
				IconItem = "TrophySkeletonPoison",
				CastAction = CastSummonRevenant,
				Describe = (int lvl) => Loc.F("spell.summon_revenant.desc", "Raise an ELITE skeleton with fearsome strength (max {0} minions)", MaxSkeletons(lvl))
			},
			new SpellDef
			{
				Name = "Bone Armor",
				UnlockLevel = 20,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "BoneFragments",
				CastAction = CastBoneArmor,
				Describe = (int lvl) => Loc.F("spell.bone_armor.desc", "Ancient bones armor you for {0:0} s", BoneArmorDuration())
			},
			new SpellDef
			{
				Name = "Bone Pact",
				UnlockLevel = 35,
				Cooldown = 60f,
				StaminaCost = 40f,
				IconItem = "BoneFragments",
				CastAction = CastBonePact,
				Describe = (int lvl) => Loc.F("spell.bone_pact.desc", "Ancient bones armor you for {0:0} s while your minions are healed and enraged (+{1}% damage for {2:0} s)", BoneArmorDuration(), PactBonusPercent(), PactDuration())
			},
			new SpellDef
			{
				Name = "Death Pact",
				UnlockLevel = 45,
				Cooldown = 45f,
				StaminaCost = 60f,
				IconItem = "TrophyDraugr",
				CastAction = CastDeathPact,
				Describe = (int lvl) => Loc.F("spell.death_pact.desc", "A pact of death erupts around you ({0} spirit, {1:0} m) healing your minions", AdjDeathPactDamage(lvl), DeathPactRadius()) + (TalentSystem.Has(LP, "dk_capstone") ? " and you" : "")
			}
		};

		private static readonly SpellDef DruidRavenForm = new SpellDef
		{
			Name = "Raven Form",
			UnlockLevel = 1,
			Cooldown = 3f,
			StaminaCost = 10f,
			IconItem = "Feathers",
			CastAction = CastRavenForm,
			Describe = (int lvl) => Loc.F("spell.raven_form.desc", "Take raven shape and fly from the ground (Jump/Space rise, Crouch/Ctrl dive; {0:0}/s stamina, {1:0}/s while encumbered). Cannot attack; cast again to land.", 4f, 8f)
		};

		private static readonly SpellDef DruidForestBlessingBase = new SpellDef
		{
			Name = "Forest Blessing",
			UnlockLevel = 1,
			Cooldown = 25f,
			StaminaCost = 25f,
			IconItem = "AncientSeed",
			CastAction = CastForestBlessing,
			Describe = (int lvl) => Loc.F("spell.forest_blessing.desc", "The wild empowers allies within {0:0} m for {1:0} s", BlessingRadius(), ForestBlessingDuration())
		};

		private static readonly SpellDef DruidRegrowthBase = new SpellDef
		{
			Name = "Regrowth",
			UnlockLevel = 1,
			Cooldown = 12f,
			StaminaCost = 25f,
			IconItem = "Dandelion",
			CastAction = CastRegrowth,
			Describe = (int lvl) => Loc.F("spell.regrowth.desc", "Life surges: you and allies within {0:0} m recover {1} HP", BlessingRadius(), AdjRegrowthHeal(lvl))
		};

		private static readonly SpellDef[] DruidWildBaseOnly = new SpellDef[1] { DruidRavenForm };

		private static readonly SpellDef[] DruidWardenBaseOnly = new SpellDef[1] { DruidForestBlessingBase };

		private static readonly SpellDef[] DruidRestoBaseOnly = new SpellDef[1] { DruidRegrowthBase };

		public static readonly SpellDef[] WerewolfSpells = new SpellDef[5]
		{
			DruidRavenForm,
			new SpellDef
			{
				Name = "Wolf Form",
				UnlockLevel = 10,
				Cooldown = 6f,
				StaminaCost = 15f,
				IconItem = "TrophyWolf",
				CastAction = CastWolfForm,
				Describe = (int lvl) => Loc.T("spell.wolf_form.desc", "Take wolf shape: faster, fiercer claws. Cast again to revert.")
			},
			new SpellDef
			{
				Name = "Savage Pounce",
				UnlockLevel = 20,
				Cooldown = 9f,
				StaminaCost = 25f,
				IconItem = "TrophyWolf",
				CastAction = CastSavagePounce,
				Describe = (int lvl) => Loc.F("spell.savage_pounce.desc", "Leap forward and rip ({0} slash, {1:0} m)", AdjSavagePounceDamage(lvl), SavagePounceRange())
			},
			new SpellDef
			{
				Name = "Savage Rend",
				UnlockLevel = 35,
				Cooldown = 10f,
				StaminaCost = 30f,
				IconItem = "Entrails",
				CastAction = CastSavageRend,
				Describe = (int lvl) => Loc.F("spell.savage_rend.desc", "Tear the foe ahead: {0} slash and bleeding ({1}/s for {2} s)", AdjSavageRendHit(lvl), AdjRendTick(lvl), RendTicks())
			},
			new SpellDef
			{
				Name = "Blood Moon",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 50f,
				IconItem = "TrophyWolf",
				CastAction = CastBloodMoon,
				Describe = (int lvl) => Loc.F("spell.blood_moon.desc", "The pack's fury: +{0}% attack for {1:0} s", BloodMoonAttack(), BloodMoonDuration()) + (TalentSystem.Has(LP, "ww_packlead") ? " (you and nearby allies)" : "")
			}
		};

		public static readonly SpellDef[] WerebearSpells = new SpellDef[5]
		{
			DruidRavenForm,
			new SpellDef
			{
				Name = "Bear Form",
				UnlockLevel = 10,
				Cooldown = 6f,
				StaminaCost = 15f,
				IconItem = "TrophyBoar",
				CastAction = CastBearForm,
				Describe = (int lvl) => Loc.T("spell.bear_form.desc", "Take bear shape: heavy, armored, crushing paws. Cast again to revert.")
			},
			new SpellDef
			{
				Name = "Maul",
				UnlockLevel = 20,
				Cooldown = 7f,
				StaminaCost = 25f,
				IconItem = "SledgeStagbreaker",
				CastAction = CastMaul,
				Describe = (int lvl) => Loc.F("spell.maul.desc", "A sweeping paw ({0} blunt, {1:0} m arc, heavy knockback)", AdjMaulDamage(lvl), MaulRadius())
			},
			new SpellDef
			{
				Name = "Thunderous Roar",
				UnlockLevel = 35,
				Cooldown = 18f,
				StaminaCost = 35f,
				IconItem = "TrophyBoar",
				CastAction = CastThunderousRoar,
				Describe = (int lvl) => Loc.F("spell.thunderous_roar.desc", "A deafening roar ({0} blunt, {1:0} m) that staggers foes", AdjRoarDamage(lvl), RoarRadius())
			},
			new SpellDef
			{
				Name = "Feral Charge",
				UnlockLevel = 45,
				Cooldown = 20f,
				StaminaCost = 45f,
				IconItem = "SledgeStagbreaker",
				CastAction = CastFeralCharge,
				Describe = (int lvl) => Loc.F("spell.feral_charge.desc", "Charge forward, trampling foes ({0} blunt, {1:0} m)", AdjFeralChargeDamage(lvl), FeralChargeRange())
			}
		};

		public static readonly SpellDef[] SkaldSpells = new SpellDef[5]
		{
			DruidForestBlessingBase,
			new SpellDef
			{
				Name = "Wind's Grace",
				UnlockLevel = 10,
				Cooldown = 30f,
				StaminaCost = 30f,
				IconItem = "Feathers",
				CastAction = CastWindsGrace,
				Describe = (int lvl) => Loc.F("spell.wind_s_grace.desc", "The wind carries allies within {0:0} m: far lighter running for {1:0} s", BlessingRadius(), WindsGraceDuration())
			},
			new SpellDef
			{
				Name = "Nature's Fury",
				UnlockLevel = 20,
				Cooldown = 30f,
				StaminaCost = 45f,
				IconItem = "TrophyAbomination",
				CastAction = CastNaturesFury,
				Describe = (int lvl) => Loc.F("spell.nature_s_fury.desc", "Allies within {0:0} m deal +{1}% pierce and poison damage for {2:0} s", NatureFuryRadius(), NatureFuryAttack(), NatureFuryDuration())
			},
			new SpellDef
			{
				Name = "Forest's Embrace",
				UnlockLevel = 35,
				Cooldown = 30f,
				StaminaCost = 50f,
				IconItem = "Honey",
				CastAction = CastForestEmbrace,
				Describe = (int lvl) => Loc.F("spell.forest_s_embrace.desc", "The forest embraces allies within {0:0} m: {1} HP and fast regeneration for {2:0} s", BlessingRadius(), AdjEmbraceHeal(lvl), EmbraceDuration())
			},
			new SpellDef
			{
				Name = "War Song",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 60f,
				IconItem = "AncientSeed",
				CastAction = CastWarSong,
				Describe = (int lvl) => Loc.F("spell.war_song.desc", "A rallying anthem: allies within {0:0} m gain +{1}% attack and +{2} armor for {3:0} s", WarSongRadius(), WarSongAttack(), WarSongArmor(), WarSongDuration())
			}
		};

		public static readonly SpellDef[] BeastmasterSpells = new SpellDef[5]
		{
			DruidForestBlessingBase,
			new SpellDef
			{
				Name = "Summon Wolf",
				UnlockLevel = 10,
				Cooldown = 10f,
				StaminaCost = 30f,
				IconItem = "TrophyWolf",
				CastAction = CastSummonWolf,
				Describe = (int lvl) => Loc.F("spell.summon_wolf.desc", "Call a wolf companion to fight for you (max {0})", MaxCompanions())
			},
			new SpellDef
			{
				Name = "Summon Bear",
				UnlockLevel = 20,
				Cooldown = 14f,
				StaminaCost = 40f,
				IconItem = "TrophyBoar",
				CastAction = CastSummonBear,
				Describe = (int lvl) => Loc.F("spell.summon_bear.desc", "Call a mighty bear companion: tough and fierce (max {0})", MaxCompanions())
			},
			new SpellDef
			{
				Name = "Forest's Embrace",
				UnlockLevel = 35,
				Cooldown = 30f,
				StaminaCost = 50f,
				IconItem = "Honey",
				CastAction = CastForestEmbrace,
				Describe = (int lvl) => Loc.F("spell.forest_s_embrace.desc", "The forest embraces allies within {0:0} m: {1} HP and fast regeneration for {2:0} s", BlessingRadius(), AdjEmbraceHeal(lvl), EmbraceDuration())
			},
			new SpellDef
			{
				Name = "Call of the Wild",
				UnlockLevel = 45,
				Cooldown = 90f,
				StaminaCost = 80f,
				IconItem = "TrophyWolf",
				CastTime = 2f,
				CastAction = CastCallOfTheWild,
				Describe = (int lvl) => Loc.F("spell.call_of_the_wild.desc", "A wild pack answers: {0} wolves rush to your side for {1:0} s", WildPackCount(), ArmyLifetime)
			}
		};

		public static readonly SpellDef[] LifekeeperSpells = new SpellDef[5]
		{
			DruidRegrowthBase,
			new SpellDef
			{
				Name = "Healing Bloom",
				UnlockLevel = 10,
				Cooldown = 30f,
				StaminaCost = 40f,
				IconItem = "Raspberry",
				CastTime = 1.5f,
				CastAction = CastHealingBloom,
				Describe = (int lvl) => Loc.F("spell.healing_bloom.desc", "A meadow of healing flowers blooms ({0:0} m, {1:0} s): allies inside recover {2} HP per second", BloomRadius(), BloomDuration(), AdjBloomHeal(lvl))
			},
			new SpellDef
			{
				Name = "Forest's Embrace",
				UnlockLevel = 20,
				Cooldown = 30f,
				StaminaCost = 50f,
				IconItem = "Honey",
				CastAction = CastForestEmbrace,
				Describe = (int lvl) => Loc.F("spell.forest_s_embrace.desc", "The forest embraces allies within {0:0} m: {1} HP and fast regeneration for {2:0} s", BlessingRadius(), AdjEmbraceHeal(lvl), EmbraceDuration())
			},
			new SpellDef
			{
				Name = "Wrath of Yggdrasil",
				UnlockLevel = 35,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "YggdrasilWood",
				CastTime = 2.5f,
				CastAction = CastWrathOfYggdrasil,
				Describe = (int lvl) => Loc.F("spell.wrath_of_yggdrasil.desc", "The World Tree answers: allies recover {0} HP and enemies take {1} pierce + poison", AdjYggdrasilHeal(lvl), AdjYggdrasilDamage(lvl))
			},
			new SpellDef
			{
				Name = "Tranquility",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 70f,
				IconItem = "Honey",
				CastTime = 1f,
				CastAction = CastTranquility,
				Describe = (int lvl) => Loc.F("spell.tranquility.desc", "A field of serenity ({0:0} m): {1} HP now, then {2} HP/s for {3:0} s", TranquilityRadius(), AdjTranquilityBurst(lvl), AdjTranquilityTick(lvl), TranquilityDuration())
			}
		};

		public static readonly SpellDef[] GrovekeeperSpells = new SpellDef[5]
		{
			DruidRegrowthBase,
			new SpellDef
			{
				Name = "Healing Bloom",
				UnlockLevel = 10,
				Cooldown = 30f,
				StaminaCost = 40f,
				IconItem = "Raspberry",
				CastTime = 1.5f,
				CastAction = CastHealingBloom,
				Describe = (int lvl) => Loc.F("spell.healing_bloom.desc", "A meadow of healing flowers blooms ({0:0} m, {1:0} s): allies inside recover {2} HP per second", BloomRadius(), BloomDuration(), AdjBloomHeal(lvl))
			},
			new SpellDef
			{
				Name = "Grasping Roots",
				UnlockLevel = 20,
				Cooldown = 15f,
				StaminaCost = 35f,
				IconItem = "Root",
				CastAction = CastGraspingRoots,
				Describe = (int lvl) => Loc.F("spell.grasping_roots.desc", "Roots erupt from the earth ({0} pierce + poison, {1:0} m) and hurl enemies away", AdjRootsDamage(lvl), RootsRadius())
			},
			new SpellDef
			{
				Name = "Wind's Grace",
				UnlockLevel = 35,
				Cooldown = 30f,
				StaminaCost = 30f,
				IconItem = "Feathers",
				CastAction = CastWindsGrace,
				Describe = (int lvl) => Loc.F("spell.wind_s_grace.desc", "The wind carries allies within {0:0} m: far lighter running for {1:0} s", BlessingRadius(), WindsGraceDuration())
			},
			new SpellDef
			{
				Name = "Barkward",
				UnlockLevel = 45,
				Cooldown = 45f,
				StaminaCost = 50f,
				IconItem = "TrollHide",
				CastAction = CastBarkward,
				Describe = (int lvl) => Loc.F("spell.barkward.desc", "Living bark shields allies within {0:0} m: +{1} armor for {2:0} s", BarkwardRadius(), BarkwardArmor(), BarkwardDuration()) + (TalentSystem.Has(LP, "gk_capstone") ? " and steady regeneration" : "")
			}
		};

		private static readonly SpellDef EinherThunderbolt = new SpellDef
		{
			Name = "Thunderbolt",
			UnlockLevel = 1,
			Cooldown = 5f,
			StaminaCost = 20f,
			IconItem = "StaffLightning",
			CastAction = CastThunderbolt,
			Describe = (int lvl) => Loc.F("spell.thunderbolt.desc", "Hurl a bolt of Thor's lightning ({0} lightning)", AdjThunderboltDamage(lvl)) + ((TalentSystem.Has(LP, "sto_notable") || TalentSystem.Has(LP, "thu_capstone")) ? ", chaining to a nearby foe" : "")
		};

		private static readonly SpellDef EinherSpearBase = new SpellDef
		{
			Name = "Spear of the Gods",
			UnlockLevel = 1,
			Cooldown = 6f,
			StaminaCost = 20f,
			IconItem = "SpearBronze",
			CastAction = CastSpearOfTheGods,
			Describe = (int lvl) => Loc.F("spell.spear_of_the_gods.desc", "Hurl a radiant spear ({0} pierce + {1} lightning)", AdjGodSpearPierce(lvl), Adj(GodSpearLightning(lvl), "lightning"))
		};

		private static readonly SpellDef EinherValkyrieBase = new SpellDef
		{
			Name = "Valkyrie's Blessing",
			UnlockLevel = 1,
			Cooldown = 30f,
			StaminaCost = 30f,
			IconItem = "TrophyValkyrie",
			CastAction = CastBattleBlessing,
			Describe = (int lvl) => Loc.F("spell.valkyrie_s_blessing.desc", "Bless allies within {0:0} m: +15% damage and swift stamina for {1:0} s", BlessingRadius(), BlessingDuration())
		};

		private static readonly SpellDef[] EinherStormBaseOnly = new SpellDef[1] { EinherThunderbolt };

		private static readonly SpellDef[] EinherSpearBaseOnly = new SpellDef[1] { EinherSpearBase };

		private static readonly SpellDef[] EinherValhallaBaseOnly = new SpellDef[1] { EinherValkyrieBase };

		public static readonly SpellDef[] ThundererSpells = new SpellDef[5]
		{
			EinherThunderbolt,
			new SpellDef
			{
				Name = "Judgement",
				UnlockLevel = 10,
				Cooldown = 14f,
				StaminaCost = 35f,
				IconItem = "Thunderstone",
				CastTime = 1.5f,
				CastAction = CastJudgement,
				Describe = (int lvl) => Loc.F("spell.judgement.desc", "{0} of Thor strike where you aim ({1} damage, {2:0} m)", JudgementBoltsText(), AdjJudgementDamage(lvl), JudgementRadius())
			},
			new SpellDef
			{
				Name = "Sky Dive",
				UnlockLevel = 20,
				Cooldown = 10f,
				StaminaCost = 25f,
				IconItem = "Feathers",
				CastAction = CastSkyDive,
				Describe = (int lvl) => Loc.F("spell.sky_dive.desc", "Leap from the sky and crash down ({0} damage, {1:0} m)", AdjSkyDiveDamage(lvl), SkyDiveRadius())
			},
			new SpellDef
			{
				Name = "Thunderclap",
				UnlockLevel = 35,
				Cooldown = 14f,
				StaminaCost = 40f,
				IconItem = "StaffLightning",
				CastAction = CastThunderclap,
				Describe = (int lvl) => Loc.F("spell.thunderclap.desc", "A burst of lightning around you ({0} lightning, {1:0} m)", AdjThunderclapDamage(lvl), ThunderclapRadius())
			},
			new SpellDef
			{
				Name = "Ragnarök",
				UnlockLevel = 45,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TrophyDragonQueen",
				CastTime = 2.5f,
				CastAction = CastRagnarok,
				Describe = (int lvl) => Loc.F("spell.ragnarok.desc", "Ascend and crash down ({0} damage, {1:0} m), then {2} bolts chain across your foes", AdjRagnarokDamage(lvl), RagnarokRadius(), RagnarokBolts())
			}
		};

		public static readonly SpellDef[] StormheraldSpells = new SpellDef[5]
		{
			EinherThunderbolt,
			new SpellDef
			{
				Name = "Judgement",
				UnlockLevel = 10,
				Cooldown = 14f,
				StaminaCost = 35f,
				IconItem = "Thunderstone",
				CastTime = 1.5f,
				CastAction = CastJudgement,
				Describe = (int lvl) => Loc.F("spell.judgement.desc", "{0} of Thor strike where you aim ({1} damage, {2:0} m)", JudgementBoltsText(), AdjJudgementDamage(lvl), JudgementRadius())
			},
			new SpellDef
			{
				Name = "Thunderstorm",
				UnlockLevel = 20,
				Cooldown = 24f,
				StaminaCost = 50f,
				IconItem = "Thunderstone",
				CastTime = 1f,
				CastAction = CastThunderstorm,
				Describe = (int lvl) => Loc.F("spell.thunderstorm.desc", "A raging storm field ({0:0} m, {1:0} s, {2} lightning/s)", ThunderstormRadius(), ThunderstormDuration(), AdjThunderstormTick(lvl))
			},
			new SpellDef
			{
				Name = "Aegis of Valhalla",
				UnlockLevel = 35,
				Cooldown = 60f,
				StaminaCost = 35f,
				IconItem = "ShieldSilver",
				CastAction = CastAegis,
				Describe = (int lvl) => Loc.F("spell.aegis_of_valhalla.desc", "Divine shield for {0:0} s and a pulse that repels nearby enemies", AegisDuration())
			},
			new SpellDef
			{
				Name = "Ragnarök",
				UnlockLevel = 45,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TrophyDragonQueen",
				CastTime = 2.5f,
				CastAction = CastRagnarok,
				Describe = (int lvl) => Loc.F("spell.ragnarok.desc", "Ascend and crash down ({0} damage, {1:0} m), then {2} bolts chain across your foes", AdjRagnarokDamage(lvl), RagnarokRadius(), RagnarokBolts())
			}
		};

		public static readonly SpellDef[] SpearmasterSpells = new SpellDef[5]
		{
			EinherSpearBase,
			new SpellDef
			{
				Name = "Spear Volley",
				UnlockLevel = 10,
				Cooldown = 12f,
				StaminaCost = 40f,
				IconItem = "SpearChitin",
				CastAction = CastSpearVolley,
				Describe = (int lvl) => Loc.F("spell.spear_volley.desc", "Fan of {0} radiant spears ({1} damage each)", VolleyCount(), AdjVolleyDamage(lvl))
			},
			new SpellDef
			{
				Name = "Sky Dive",
				UnlockLevel = 20,
				Cooldown = 10f,
				StaminaCost = 25f,
				IconItem = "Feathers",
				CastAction = CastSkyDive,
				Describe = (int lvl) => Loc.F("spell.sky_dive.desc", "Leap from the sky and crash down ({0} damage, {1:0} m)", AdjSkyDiveDamage(lvl), SkyDiveRadius())
			},
			new SpellDef
			{
				Name = "Battle Blessing",
				UnlockLevel = 35,
				Cooldown = 30f,
				StaminaCost = 25f,
				IconItem = "MeadStaminaMedium",
				CastAction = CastBattleBlessing,
				Describe = (int lvl) => Loc.F("spell.battle_blessing.desc", "+{0}% damage, swift stamina and cheap attacks for {1:0} s", BlessingAttack(), BlessingDuration())
			},
			new SpellDef
			{
				Name = "Skyfall Spears",
				UnlockLevel = 45,
				Cooldown = 30f,
				StaminaCost = 60f,
				IconItem = "SpearChitin",
				CastTime = 1.5f,
				CastAction = CastSkyfallSpears,
				Describe = (int lvl) => Loc.F("spell.skyfall_spears.desc", "{0} divine spears rain down ({1} pierce each)", SkyfallCount(), AdjSkyfallDamage(lvl))
			}
		};

		public static readonly SpellDef[] ValkyrieKnightSpells = new SpellDef[5]
		{
			EinherSpearBase,
			new SpellDef
			{
				Name = "Sky Dive",
				UnlockLevel = 10,
				Cooldown = 10f,
				StaminaCost = 25f,
				IconItem = "Feathers",
				CastAction = CastSkyDive,
				Describe = (int lvl) => Loc.F("spell.sky_dive.desc", "Leap from the sky and crash down ({0} damage, {1:0} m)", AdjSkyDiveDamage(lvl), SkyDiveRadius())
			},
			new SpellDef
			{
				Name = "Battle Blessing",
				UnlockLevel = 20,
				Cooldown = 30f,
				StaminaCost = 25f,
				IconItem = "MeadStaminaMedium",
				CastAction = CastBattleBlessing,
				Describe = (int lvl) => Loc.F("spell.battle_blessing.desc", "+{0}% damage, swift stamina and cheap attacks for {1:0} s", BlessingAttack(), BlessingDuration())
			},
			new SpellDef
			{
				Name = "Judgement",
				UnlockLevel = 35,
				Cooldown = 14f,
				StaminaCost = 35f,
				IconItem = "Thunderstone",
				CastTime = 1.5f,
				CastAction = CastJudgement,
				Describe = (int lvl) => Loc.F("spell.judgement.desc", "{0} of Thor strike where you aim ({1} damage, {2:0} m)", JudgementBoltsText(), AdjJudgementDamage(lvl), JudgementRadius())
			},
			new SpellDef
			{
				Name = "Ragnarök",
				UnlockLevel = 45,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TrophyDragonQueen",
				CastTime = 2.5f,
				CastAction = CastRagnarok,
				Describe = (int lvl) => Loc.F("spell.ragnarok.desc", "Ascend and crash down ({0} damage, {1:0} m), then {2} bolts chain across your foes", AdjRagnarokDamage(lvl), RagnarokRadius(), RagnarokBolts())
			}
		};

		public static readonly SpellDef[] ValkyrieSpells = new SpellDef[5]
		{
			EinherValkyrieBase,
			new SpellDef
			{
				Name = "Aegis of the Host",
				UnlockLevel = 10,
				Cooldown = 60f,
				StaminaCost = 35f,
				IconItem = "ShieldSilver",
				CastAction = CastAegis,
				Describe = (int lvl) => Loc.F("spell.aegis_of_the_host.desc", "Divine shield for {0:0} s: allies within {1:0} m are protected AND empowered", AegisDuration(), ValkyrieRadius())
			},
			new SpellDef
			{
				Name = "Honor Guard",
				UnlockLevel = 20,
				Cooldown = 20f,
				StaminaCost = 50f,
				IconItem = "TrophyWraith",
				CastAction = CastCallTheFallen,
				Describe = (int lvl) => Loc.F("spell.honor_guard.desc", "Summon honored spirits (max {0}) whose presence invigorates allies within {1:0} m", SpiritCap(), ValkyrieRadius())
			},
			new SpellDef
			{
				Name = "Valhalla's Grace",
				UnlockLevel = 35,
				Cooldown = 30f,
				StaminaCost = 50f,
				IconItem = "MeadHealthMedium",
				CastAction = CastValhallaGrace,
				Describe = (int lvl) => Loc.F("spell.valhalla_s_grace.desc", "The Valkyries mend the host within {0:0} m: {1} HP and fast regeneration for {2:0} s", GraceRadius(), AdjGraceHeal(lvl), GraceDuration())
			},
			new SpellDef
			{
				Name = "Ragnarök",
				UnlockLevel = 45,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TrophyDragonQueen",
				CastTime = 2.5f,
				CastAction = CastRagnarok,
				Describe = (int lvl) => Loc.F("spell.ragnarok.desc", "Ascend and crash down ({0} damage, {1:0} m), then {2} bolts chain across your foes", AdjRagnarokDamage(lvl), RagnarokRadius(), RagnarokBolts())
			}
		};

		public static readonly SpellDef[] HeraldSpells = new SpellDef[5]
		{
			EinherValkyrieBase,
			new SpellDef
			{
				Name = "Call the Fallen",
				UnlockLevel = 10,
				Cooldown = 20f,
				StaminaCost = 50f,
				IconItem = "TrophyWraith",
				CastAction = CastCallTheFallen,
				Describe = (int lvl) => Loc.F("spell.call_the_fallen.desc", "Summon fallen warriors that fight for you (max {0})", SpiritCap())
			},
			new SpellDef
			{
				Name = "Soul Spear",
				UnlockLevel = 20,
				Cooldown = 6f,
				StaminaCost = 25f,
				IconItem = "SpearChitin",
				CastAction = CastSoulSpear,
				Describe = (int lvl) => Loc.F("spell.soul_spear.desc", "Hurl a spear of souls ({0} spirit)", AdjSoulSpearDamage(lvl)) + (TalentSystem.Has(LP, "her_notable") ? ", piercing through foes" : "")
			},
			new SpellDef
			{
				Name = "Wail of the Fallen",
				UnlockLevel = 35,
				Cooldown = 14f,
				StaminaCost = 40f,
				IconItem = "TrophyWraith",
				CastAction = CastWailOfTheFallen,
				Describe = (int lvl) => Loc.F("spell.wail_of_the_fallen.desc", "A wail of the dead erupts around you ({0} spirit, {1:0} m)", AdjSoulWailDamage(lvl), SoulWailRadius())
			},
			new SpellDef
			{
				Name = "Legion of Valhalla",
				UnlockLevel = 45,
				Cooldown = 90f,
				StaminaCost = 80f,
				IconItem = "TrophyDraugrElite",
				CastTime = 2f,
				CastAction = CastLegionOfValhalla,
				Describe = (int lvl) => Loc.F("spell.legion_of_valhalla.desc", "{0} spirit warriors rise for {1:0} s to fight at your side", HeraldLegionCount(), HeraldLegionLifetime())
			}
		};

		public static readonly SpellDef[] EinherjarSpells = new SpellDef[8]
		{
			new SpellDef
			{
				Name = "Spear of the Gods",
				UnlockLevel = 10,
				Cooldown = 6f,
				StaminaCost = 20f,
				IconItem = "SpearBronze",
				CastAction = CastSpearOfTheGods,
				Describe = (int lvl) => Loc.F("spell.spear_of_the_gods.desc.damage", "Hurl a radiant spear ({0} pierce + {1} lightning damage)", AdjGodSpearPierce(lvl), Adj(GodSpearLightning(lvl), "lightning"))
			},
			new SpellDef
			{
				Name = "Sky Dive",
				UnlockLevel = 20,
				Cooldown = 10f,
				StaminaCost = 25f,
				IconItem = "Feathers",
				CastAction = CastSkyDive,
				Describe = (int lvl) => Loc.F("spell.sky_dive.desc", "Leap forward from the sky and crash down ({0} damage, 5 m)", AdjSkyDiveDamage(lvl))
			},
			new SpellDef
			{
				Name = "Battle Blessing",
				UnlockLevel = 30,
				Cooldown = 30f,
				StaminaCost = 25f,
				IconItem = "MeadStaminaMedium",
				CastAction = CastBattleBlessing,
				Describe = (int lvl) => Loc.F("spell.battle_blessing.desc", "+15% damage, swift stamina and cheap attacks for {0:0} s", BlessingDuration())
			},
			new SpellDef
			{
				Name = "Judgement",
				UnlockLevel = 40,
				Cooldown = 14f,
				StaminaCost = 35f,
				IconItem = "Thunderstone",
				CastTime = 1.5f,
				CastAction = CastJudgement,
				Describe = (int lvl) => Loc.F("spell.judgement.desc.single", "{0} of Thor strikes where you aim ({1} damage, {2:0} m)", JudgementBoltsText(), AdjJudgementDamage(lvl), JudgementRadius())
			},
			new SpellDef
			{
				Name = "Spear Volley",
				UnlockLevel = 50,
				Cooldown = 12f,
				StaminaCost = 40f,
				IconItem = "SpearChitin",
				CastAction = CastSpearVolley,
				Describe = (int lvl) => Loc.F("spell.spear_volley.desc", "Fan of {0} radiant spears ({1} damage each)", VolleyCount(), AdjVolleyDamage(lvl))
			},
			new SpellDef
			{
				Name = "Aegis of Valhalla",
				UnlockLevel = 60,
				Cooldown = 60f,
				StaminaCost = 35f,
				IconItem = "ShieldSilver",
				CastAction = CastAegis,
				Describe = (int lvl) => Loc.F("spell.aegis_of_valhalla.desc", "Divine shield for {0:0} s and a pulse that repels nearby enemies", AegisDuration())
			},
			new SpellDef
			{
				Name = "Call the Fallen",
				UnlockLevel = 70,
				Cooldown = 20f,
				StaminaCost = 50f,
				IconItem = "TrophyWraith",
				CastAction = CastCallTheFallen,
				Describe = (int lvl) => Loc.F("spell.call_the_fallen.desc", "Summon fallen warriors that fight for you (max {0})", SpiritCap())
			},
			new SpellDef
			{
				Name = "Ragnarök",
				UnlockLevel = 80,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TrophyDragonQueen",
				CastTime = 2.5f,
				CastAction = CastRagnarok,
				Describe = (int lvl) => Loc.F("spell.ragnarok.desc", "Ascend and crash down ({0} damage, 12 m), then {1} bolts chain across your foes", AdjRagnarokDamage(lvl), RagnarokBolts())
			}
		};

		public static readonly SpellDef[] ChosenSpells = new SpellDef[8]
		{
			new SpellDef
			{
				Name = "Spear of the Gods",
				UnlockLevel = 10,
				Cooldown = 8f,
				StaminaCost = 25f,
				IconItem = "SpearBronze",
				CastAction = CastSpearOfTheGods,
				Describe = (int lvl) => Loc.F("spell.spear_of_the_gods.desc", "Hurl a radiant spear ({0} pierce + {1} lightning)", AdjGodSpearPierce(lvl), Adj(GodSpearLightning(lvl), "lightning"))
			},
			new SpellDef
			{
				Name = "Sky Dive",
				UnlockLevel = 20,
				Cooldown = 12f,
				StaminaCost = 25f,
				IconItem = "Feathers",
				CastAction = CastSkyDive,
				Describe = (int lvl) => Loc.F("spell.sky_dive.desc", "Leap from the sky and crash down ({0} damage, 5 m)", AdjSkyDiveDamage(lvl))
			},
			new SpellDef
			{
				Name = "Valkyrie's Blessing",
				UnlockLevel = 30,
				Cooldown = 30f,
				StaminaCost = 30f,
				IconItem = "TrophyValkyrie",
				CastAction = CastBattleBlessing,
				Describe = (int lvl) => Loc.F("spell.valkyrie_s_blessing.desc", "Bless yourself and allies within {0:0} m: +15% damage, swift stamina and cheap attacks for {1:0} s", 8f + ValkyrieReachBonus(LP), BlessingDuration())
			},
			new SpellDef
			{
				Name = "Judgement",
				UnlockLevel = 40,
				Cooldown = 14f,
				StaminaCost = 35f,
				IconItem = "Thunderstone",
				CastTime = 1.5f,
				CastAction = CastJudgement,
				Describe = (int lvl) => Loc.F("spell.judgement.desc.single", "{0} of Thor strikes where you aim ({1} damage, {2:0} m)", JudgementBoltsText(), AdjJudgementDamage(lvl), JudgementRadius())
			},
			new SpellDef
			{
				Name = "Spear Volley",
				UnlockLevel = 50,
				Cooldown = 12f,
				StaminaCost = 40f,
				IconItem = "SpearChitin",
				CastAction = CastSpearVolley,
				Describe = (int lvl) => Loc.F("spell.spear_volley.desc", "Fan of {0} radiant spears ({1} damage each)", VolleyCount(), AdjVolleyDamage(lvl))
			},
			new SpellDef
			{
				Name = "Aegis of the Host",
				UnlockLevel = 60,
				Cooldown = 60f,
				StaminaCost = 35f,
				IconItem = "ShieldSilver",
				CastAction = CastAegis,
				Describe = (int lvl) => Loc.F("spell.aegis_of_the_host.desc", "Divine shield for {0:0} s: allies within {1:0} m are protected AND empowered", AegisDuration(), 8f + ValkyrieReachBonus(LP))
			},
			new SpellDef
			{
				Name = "Honor Guard",
				UnlockLevel = 70,
				Cooldown = 20f,
				StaminaCost = 50f,
				IconItem = "TrophyWraith",
				CastAction = CastCallTheFallen,
				Describe = (int lvl) => Loc.F("spell.honor_guard.desc", "Summon honored spirits (max {0}) — their presence invigorates allies within {1:0} m", SpiritCap(), 6f + ValkyrieReachBonus(LP))
			},
			new SpellDef
			{
				Name = "Ragnarök",
				UnlockLevel = 80,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TrophyDragonQueen",
				CastTime = 2.5f,
				CastAction = CastRagnarok,
				Describe = (int lvl) => Loc.F("spell.ragnarok.desc", "Ascend and crash down ({0} damage, 12 m), then {1} bolts chain across your foes", AdjRagnarokDamage(lvl), RagnarokBolts())
			}
		};

		public static readonly SpellDef[] GuardianSpells = new SpellDef[8]
		{
			new SpellDef
			{
				Name = "Shield Bash",
				UnlockLevel = 10,
				Cooldown = 6f,
				StaminaCost = 15f,
				IconItem = "ShieldBanded",
				CastAction = CastShieldBash,
				Describe = (int lvl) => Loc.F("spell.shield_bash.desc", "Slam your shield forward ({0} damage) and force the foes you hit to face YOU", AdjBashDamage(lvl))
			},
			new SpellDef
			{
				Name = "Challenge",
				UnlockLevel = 20,
				Cooldown = 14f,
				StaminaCost = 20f,
				IconItem = "ShieldWood",
				CastAction = CastChallenge,
				Describe = (int lvl) => Loc.F("spell.challenge.desc", "Every enemy within {0:0} m turns on you; your defiance grants bonus armor for 8 s", ChallengeRadius())
			},
			new SpellDef
			{
				Name = "Shield Wall",
				UnlockLevel = 30,
				Cooldown = 60f,
				StaminaCost = 40f,
				IconItem = "ShieldIronTower",
				CastAction = CastShieldWall,
				Describe = (int lvl) => Loc.F("spell.shield_wall.desc", "Skjaldborg! A golden dome ({0:0} m, {1:0} s): armors allies inside, shatters projectiles, repels enemies", ShieldWallRadius(), ShieldWallDuration())
			},
			new SpellDef
			{
				Name = "Guardian's Leap",
				UnlockLevel = 40,
				Cooldown = 12f,
				StaminaCost = 25f,
				IconItem = "ShieldBronzeBuckler",
				CastAction = CastGuardianLeap,
				Describe = (int lvl) => Loc.F("spell.guardian_s_leap.desc", "Leap to your fellows ({0} damage on landing) and shield allies around you for {1:0} s", AdjLeapDamage(lvl), RampartDuration())
			},
			new SpellDef
			{
				Name = "Iron Bulwark",
				UnlockLevel = 50,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "ArmorPaddedCuirass",
				CastAction = CastIronBulwark,
				Describe = (int lvl) => Loc.F("spell.iron_bulwark.desc", "Become an unmovable wall for {0:0} s", BulwarkDuration())
			},
			new SpellDef
			{
				Name = "Ground Slam",
				UnlockLevel = 60,
				Cooldown = 18f,
				StaminaCost = 35f,
				IconItem = "SledgeIron",
				CastAction = CastGroundSlam,
				Describe = (int lvl) => Loc.F("spell.ground_slam.desc", "Shake the earth ({0} damage, {1:0} m) and taunt every enemy you hit", AdjStompDamage(lvl), StompRadius())
			},
			new SpellDef
			{
				Name = "Living Fortress",
				UnlockLevel = 70,
				Cooldown = 45f,
				StaminaCost = 35f,
				IconItem = "ShieldSerpentscale",
				CastAction = CastLivingFortress,
				Describe = (int lvl) => Loc.F("spell.living_fortress.desc", "Immense armor for {0:0} s while your presence keeps taunting nearby enemies", FortressDuration())
			},
			new SpellDef
			{
				Name = "Gjallarhorn",
				UnlockLevel = 80,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TankardOdin",
				CastAction = CastGjallarhorn,
				Describe = (int lvl) => Loc.F("spell.gjallarhorn.desc", "Sound Heimdall's horn: {0} damage and a mighty blast ({1:0} m), while allies gain your rampart", AdjHornDamage(lvl), HornRadius())
			}
		};

		public static readonly SpellDef[] DruidSpells = new SpellDef[8]
		{
			new SpellDef
			{
				Name = "Regrowth",
				UnlockLevel = 10,
				Cooldown = 12f,
				StaminaCost = 25f,
				IconItem = "Dandelion",
				CastAction = CastRegrowth,
				Describe = (int lvl) => Loc.F("spell.regrowth.desc", "Life surges anew: you and allies within {0:0} m recover {1} HP", BlessingRadius(), AdjRegrowthHeal(lvl))
			},
			new SpellDef
			{
				Name = "Thorn Burst",
				UnlockLevel = 20,
				Cooldown = 6f,
				StaminaCost = 15f,
				IconItem = "Thistle",
				CastAction = CastThornBurst,
				Describe = (int lvl) => Loc.F("spell.thorn_burst.desc", "A burst of thorns erupts in front of you ({0} pierce damage)", AdjThornDamage(lvl))
			},
			new SpellDef
			{
				Name = "Forest Blessing",
				UnlockLevel = 30,
				Cooldown = 25f,
				StaminaCost = 25f,
				IconItem = "AncientSeed",
				CastAction = CastForestBlessing,
				Describe = (int lvl) => Loc.F("spell.forest_blessing.desc", "The wild empowers allies within {0:0} m: +{1}% attack and swift stamina for {2:0} s", BlessingRadius(), TalentSystem.Has(LP, "dru_inspiring") ? 25 : 15, ForestBlessingDuration())
			},
			new SpellDef
			{
				Name = "Healing Bloom",
				UnlockLevel = 40,
				Cooldown = 30f,
				StaminaCost = 40f,
				IconItem = "Raspberry",
				CastTime = 1.5f,
				CastAction = CastHealingBloom,
				Describe = (int lvl) => Loc.F("spell.healing_bloom.desc", "A meadow of healing flowers blooms ({0:0} m, {1:0} s): allies standing inside recover {2} HP per second", BloomRadius(), BloomDuration(), AdjBloomHeal(lvl))
			},
			new SpellDef
			{
				Name = "Wind's Grace",
				UnlockLevel = 50,
				Cooldown = 30f,
				StaminaCost = 30f,
				IconItem = "Feathers",
				CastAction = CastWindsGrace,
				Describe = (int lvl) => Loc.F("spell.wind_s_grace.desc", "The wind carries allies within {0:0} m: far lighter running for {1:0} s", BlessingRadius(), WindsGraceDuration())
			},
			new SpellDef
			{
				Name = "Grasping Roots",
				UnlockLevel = 60,
				Cooldown = 15f,
				StaminaCost = 35f,
				IconItem = "Root",
				CastAction = CastGraspingRoots,
				Describe = (int lvl) => Loc.F("spell.grasping_roots.desc", "Roots erupt from the earth ({0} pierce + poison damage, {1:0} m) and hurl enemies away", AdjRootsDamage(lvl), RootsRadius())
			},
			new SpellDef
			{
				Name = "Forest's Embrace",
				UnlockLevel = 70,
				Cooldown = 30f,
				StaminaCost = 50f,
				IconItem = "Honey",
				CastAction = CastForestEmbrace,
				Describe = (int lvl) => Loc.F("spell.forest_s_embrace.desc", "The forest embraces allies within {0:0} m: {1} HP recovered and fast regeneration for {2:0} s", BlessingRadius(), AdjEmbraceHeal(lvl), EmbraceDuration())
			},
			new SpellDef
			{
				Name = "Wrath of Yggdrasil",
				UnlockLevel = 80,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "YggdrasilWood",
				CastTime = 2.5f,
				CastAction = CastWrathOfYggdrasil,
				Describe = (int lvl) => Loc.F("spell.wrath_of_yggdrasil.desc", "The World Tree answers: allies recover {0} HP and gain its blessing, enemies take {1} pierce + poison damage from the erupting roots", AdjYggdrasilHeal(lvl), AdjYggdrasilDamage(lvl))
			}
		};

		public static readonly SpellDef[] VanguardSpells = new SpellDef[8]
		{
			new SpellDef
			{
				Name = "Skull Crusher",
				UnlockLevel = 10,
				Cooldown = 6f,
				StaminaCost = 15f,
				IconItem = "MaceBronze",
				CastAction = CastShieldBash,
				Describe = (int lvl) => Loc.F("spell.skull_crusher.desc", "A merciless shield slam ({0} damage, huge knockback)", AdjBashDamage(lvl))
			},
			new SpellDef
			{
				Name = "Shattering Shout",
				UnlockLevel = 20,
				Cooldown = 8f,
				StaminaCost = 20f,
				IconItem = "Club",
				CastAction = CastShatteringShout,
				Describe = (int lvl) => Loc.F("spell.shattering_shout.desc", "A shout that shatters bone ({0} damage in a 6 m wave of force)", AdjShoutDamage(lvl))
			},
			new SpellDef
			{
				Name = "Assault Leap",
				UnlockLevel = 30,
				Cooldown = 12f,
				StaminaCost = 25f,
				IconItem = "ShieldBronzeBuckler",
				CastAction = CastGuardianLeap,
				Describe = (int lvl) => Loc.F("spell.guardian_s_leap.desc", "Leap into the fray ({0} damage on landing){1}", AdjLeapDamage(lvl), TalentSystem.Has(LP, "vg_leapfrenzy") ? Loc.T("spell.guardian_s_leap.desc.frenzy", " and fuel your frenzy (+15% attack)") : string.Empty)
			},
			new SpellDef
			{
				Name = "Rupture",
				UnlockLevel = 40,
				Cooldown = 18f,
				StaminaCost = 35f,
				IconItem = "SledgeIron",
				CastAction = CastGroundSlam,
				Describe = (int lvl) => Loc.F("spell.ground_slam.desc", "Tear the earth open ({0} damage, {1:0} m){2}", AdjStompDamage(lvl), StompRadius(), TalentSystem.Has(LP, "vg_aftershock") ? Loc.T("spell.ground_slam.desc.aftershock", " - strikes twice") : string.Empty)
			},
			new SpellDef
			{
				Name = "Battle Plates",
				UnlockLevel = 50,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "ArmorPaddedCuirass",
				CastAction = CastIronBulwark,
				Describe = (int lvl) => Loc.F("spell.battle_plates.desc", "War plates for {0:0} s{1}", BulwarkDuration(), TalentSystem.Has(LP, "vg_berserkplate") ? Loc.T("spell.battle_plates.desc.berserk", ", fueling your attacks (+10%)") : string.Empty)
			},
			new SpellDef
			{
				Name = "Shield Storm",
				UnlockLevel = 60,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "ShieldIronSquare",
				CastAction = CastShieldStorm,
				Describe = (int lvl) => Loc.F("spell.shield_storm.desc", "Spin with your shield out for 2 s ({0} damage per hit, 4 m)", AdjStormTickDamage(lvl))
			},
			new SpellDef
			{
				Name = "Battle Frenzy",
				UnlockLevel = 70,
				Cooldown = 45f,
				StaminaCost = 35f,
				IconItem = "TrophyFenring",
				CastAction = CastLivingFortress,
				Describe = (int lvl) => Loc.F("spell.living_fortress.desc", "Immense armor and battle frenzy (+{0}% attack) for {1:0} s", TalentSystem.Has(LP, "vg_frenzyfort") ? 25 : 15, FortressDuration())
			},
			new SpellDef
			{
				Name = "Horn of War",
				UnlockLevel = 80,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TankardOdin",
				CastAction = CastGjallarhorn,
				Describe = (int lvl) => Loc.F("spell.horn_of_war.desc", "A devastating war blast ({0} damage, {1:0} m)", AdjHornDamage(lvl), HornRadius())
			}
		};

		private static readonly SpellDef GuardShieldBash = new SpellDef
		{
			Name = "Shield Bash",
			UnlockLevel = 1,
			Cooldown = 6f,
			StaminaCost = 15f,
			IconItem = "ShieldBanded",
			CastAction = CastShieldBash,
			Describe = (int lvl) => Loc.F("spell.shield_bash.desc", "Slam your shield forward ({0} damage) and force the foes you hit to face YOU", AdjBashDamage(lvl))
		};

		private static readonly SpellDef VanSkullCrusher = new SpellDef
		{
			Name = "Skull Crusher",
			UnlockLevel = 1,
			Cooldown = 6f,
			StaminaCost = 15f,
			IconItem = "MaceBronze",
			CastAction = CastShieldBash,
			Describe = (int lvl) => Loc.F("spell.skull_crusher.desc", "A merciless shield slam ({0} damage, huge knockback)", AdjBashDamage(lvl))
		};

		private static readonly SpellDef PalBlessingBase = new SpellDef
		{
			Name = "Blessing of Light",
			UnlockLevel = 1,
			Cooldown = 30f,
			StaminaCost = 25f,
			IconItem = "TrophyValkyrie",
			CastAction = CastBlessingOfLight,
			Describe = (int lvl) => Loc.F("spell.blessing_of_light.desc", "Bless allies within {0:0} m: +{1}% attack and +{2} armor for {3:0} s", HolyRadius(), BlessLightAttack(), BlessLightArmor(), HolyBuffDuration()) + ((TalentSystem.Has(LP, "tmp_capstone") || TalentSystem.Has(LP, "pal_notable")) ? ", mending the wounded" : "")
		};

		private static readonly SpellDef[] GuardianBulwarkBaseOnly = new SpellDef[1] { GuardShieldBash };

		private static readonly SpellDef[] GuardianVanguardBaseOnly = new SpellDef[1] { VanSkullCrusher };

		private static readonly SpellDef[] GuardianPaladinBaseOnly = new SpellDef[1] { PalBlessingBase };

		public static readonly SpellDef[] TemplarSpells = new SpellDef[5]
		{
			PalBlessingBase,
			new SpellDef
			{
				Name = "Consecration",
				UnlockLevel = 10,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "Honey",
				CastTime = 1f,
				CastAction = CastConsecration,
				Describe = (int lvl) => Loc.F("spell.consecration.desc", "Hallow the ground ({0:0} m, {1:0} s): allies inside recover {2} HP/s", HolyGroundRadius(), HolyGroundDuration(), AdjConsecrationHeal(lvl))
			},
			new SpellDef
			{
				Name = "Lay on Hands",
				UnlockLevel = 20,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "MeadHealthMedium",
				CastAction = CastLayOnHands,
				Describe = (int lvl) => Loc.F("spell.lay_on_hands.desc", "A surge of light: you and allies within {0:0} m recover {1} HP", HolyRadius(), AdjLayOnHandsHeal(lvl))
			},
			new SpellDef
			{
				Name = "Divine Shield",
				UnlockLevel = 35,
				Cooldown = 45f,
				StaminaCost = 35f,
				IconItem = "ShieldSilver",
				CastAction = CastDivineShield,
				Describe = (int lvl) => Loc.F("spell.divine_shield.desc", "A radiant ward covers allies within {0:0} m: +{1} armor for {2:0} s", HolyRadius(), DivineShieldArmor(), DivineShieldDuration())
			},
			new SpellDef
			{
				Name = "Beacon of Light",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 70f,
				IconItem = "TrophyValkyrie",
				CastTime = 1f,
				CastAction = CastBeaconOfLight,
				Describe = (int lvl) => Loc.F("spell.beacon_of_light.desc", "A beacon blazes ({0:0} m): {1} HP now and fast regeneration for {2:0} s", HolyRadius(), AdjBeaconHeal(lvl), BeaconDuration())
			}
		};

		public static readonly SpellDef[] LightbringerSpells = new SpellDef[5]
		{
			PalBlessingBase,
			new SpellDef
			{
				Name = "Smite",
				UnlockLevel = 10,
				Cooldown = 5f,
				StaminaCost = 20f,
				IconItem = "StaffLightning",
				CastAction = CastSmite,
				Describe = (int lvl) => Loc.F("spell.smite.desc", "Call down holy light ({0} spirit)", AdjSmiteDamage(lvl)) + (TalentSystem.Has(LP, "lbr_notable") ? ", piercing through foes" : "")
			},
			new SpellDef
			{
				Name = "Holy Nova",
				UnlockLevel = 20,
				Cooldown = 12f,
				StaminaCost = 35f,
				IconItem = "TrophyValkyrie",
				CastAction = CastHolyNova,
				Describe = (int lvl) => Loc.F("spell.holy_nova.desc", "A burst of light around you ({0} spirit, {1:0} m)", AdjHolyNovaDamage(lvl), HolyNovaRadius())
			},
			new SpellDef
			{
				Name = "Consecration",
				UnlockLevel = 35,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "StaffLightning",
				CastTime = 1f,
				CastAction = CastConsecration,
				Describe = (int lvl) => Loc.F("spell.consecration.desc", "Searing hallowed ground ({0:0} m, {1:0} s): enemies inside take {2} spirit/s", HolyGroundRadius(), HolyGroundDuration(), AdjConsecrationDamage(lvl))
			},
			new SpellDef
			{
				Name = "Wrath of Light",
				UnlockLevel = 45,
				Cooldown = 60f,
				StaminaCost = 80f,
				IconItem = "TrophyDragonQueen",
				CastTime = 1.5f,
				CastAction = CastWrathOfLight,
				Describe = (int lvl) => Loc.F("spell.wrath_of_light.desc", "The heavens answer ({0} spirit, {1:0} m)", AdjWrathDamage(lvl), WrathRadius()) + (TalentSystem.Has(LP, "lbr_wrathheal") ? " and heals you per foe struck" : "")
			}
		};

		public static readonly SpellDef[] WardenGuardSpells = new SpellDef[5]
		{
			GuardShieldBash,
			new SpellDef
			{
				Name = "Challenge",
				UnlockLevel = 10,
				Cooldown = 14f,
				StaminaCost = 20f,
				IconItem = "ShieldWood",
				CastAction = CastChallenge,
				Describe = (int lvl) => Loc.F("spell.challenge.desc", "Every enemy within {0:0} m turns on you; your defiance grants bonus armor for 8 s", ChallengeRadius())
			},
			new SpellDef
			{
				Name = "Shield Wall",
				UnlockLevel = 20,
				Cooldown = 60f,
				StaminaCost = 40f,
				IconItem = "ShieldIronTower",
				CastAction = CastShieldWall,
				Describe = (int lvl) => Loc.F("spell.shield_wall.desc", "Skjaldborg! A golden dome ({0:0} m, {1:0} s): armors allies inside, shatters projectiles, repels enemies", ShieldWallRadius(), ShieldWallDuration())
			},
			new SpellDef
			{
				Name = "Living Fortress",
				UnlockLevel = 35,
				Cooldown = 45f,
				StaminaCost = 35f,
				IconItem = "ShieldSerpentscale",
				CastAction = CastLivingFortress,
				Describe = (int lvl) => Loc.F("spell.living_fortress.desc", "Immense armor for {0:0} s while your presence keeps taunting nearby enemies", FortressDuration())
			},
			new SpellDef
			{
				Name = "Gjallarhorn",
				UnlockLevel = 45,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TankardOdin",
				CastAction = CastGjallarhorn,
				Describe = (int lvl) => Loc.F("spell.gjallarhorn.desc", "Sound Heimdall's horn: {0} damage and a mighty blast ({1:0} m), while allies gain your rampart", AdjHornDamage(lvl), HornRadius())
			}
		};

		public static readonly SpellDef[] SentinelSpells = new SpellDef[5]
		{
			GuardShieldBash,
			new SpellDef
			{
				Name = "Iron Bulwark",
				UnlockLevel = 10,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "ArmorPaddedCuirass",
				CastAction = CastIronBulwark,
				Describe = (int lvl) => Loc.F("spell.iron_bulwark.desc", "Become an unmovable wall for {0:0} s", BulwarkDuration())
			},
			new SpellDef
			{
				Name = "Challenge",
				UnlockLevel = 20,
				Cooldown = 14f,
				StaminaCost = 20f,
				IconItem = "ShieldWood",
				CastAction = CastChallenge,
				Describe = (int lvl) => Loc.F("spell.challenge.desc", "Every enemy within {0:0} m turns on you; your defiance grants bonus armor for 8 s", ChallengeRadius())
			},
			new SpellDef
			{
				Name = "Thornplate",
				UnlockLevel = 35,
				Cooldown = 45f,
				StaminaCost = 30f,
				IconItem = "ShieldSerpentscale",
				CastAction = CastThornplate,
				Describe = (int lvl) => Loc.F("spell.thornplate.desc", "Spiked bulwark for {0:0} s: attackers take {1} damage back", ThornplateDuration(), ThornplateReflect(lvl))
			},
			new SpellDef
			{
				Name = "Gjallarhorn",
				UnlockLevel = 45,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TankardOdin",
				CastAction = CastGjallarhorn,
				Describe = (int lvl) => Loc.F("spell.gjallarhorn.desc", "Sound Heimdall's horn: {0} damage and a mighty blast ({1:0} m), while allies gain your rampart", AdjHornDamage(lvl), HornRadius())
			}
		};

		public static readonly SpellDef[] CrusherSpells = new SpellDef[5]
		{
			VanSkullCrusher,
			new SpellDef
			{
				Name = "Ground Slam",
				UnlockLevel = 10,
				Cooldown = 18f,
				StaminaCost = 35f,
				IconItem = "SledgeIron",
				CastAction = CastGroundSlam,
				Describe = (int lvl) => Loc.F("spell.ground_slam.desc", "Shake the earth ({0} damage, {1:0} m)", AdjStompDamage(lvl), StompRadius())
			},
			new SpellDef
			{
				Name = "Assault Leap",
				UnlockLevel = 20,
				Cooldown = 12f,
				StaminaCost = 25f,
				IconItem = "ShieldBronzeBuckler",
				CastAction = CastGuardianLeap,
				Describe = (int lvl) => Loc.F("spell.assault_leap.desc", "Leap into the fray ({0} damage on landing)", AdjLeapDamage(lvl))
			},
			new SpellDef
			{
				Name = "Shield Storm",
				UnlockLevel = 35,
				Cooldown = 20f,
				StaminaCost = 40f,
				IconItem = "ShieldIronSquare",
				CastAction = CastShieldStorm,
				Describe = (int lvl) => Loc.F("spell.shield_storm.desc", "Spin with your shield out for 2 s ({0} damage per hit, 4 m)", AdjStormTickDamage(lvl))
			},
			new SpellDef
			{
				Name = "Earthbreaker",
				UnlockLevel = 45,
				Cooldown = 45f,
				StaminaCost = 60f,
				IconItem = "SledgeDemolisher",
				CastTime = 1f,
				CastAction = CastEarthbreaker,
				Describe = (int lvl) => Loc.F("spell.earthbreaker.desc", "Shatter the ground ({0} damage, {1:0} m) with a devastating quake", AdjEarthbreakerDamage(lvl), EarthbreakerRadius())
			}
		};

		public static readonly SpellDef[] WarbringerSpells = new SpellDef[5]
		{
			VanSkullCrusher,
			new SpellDef
			{
				Name = "Assault Leap",
				UnlockLevel = 10,
				Cooldown = 12f,
				StaminaCost = 25f,
				IconItem = "ShieldBronzeBuckler",
				CastAction = CastGuardianLeap,
				Describe = (int lvl) => Loc.F("spell.assault_leap.desc", "Leap into the fray ({0} damage on landing)", AdjLeapDamage(lvl))
			},
			new SpellDef
			{
				Name = "Battle Frenzy",
				UnlockLevel = 20,
				Cooldown = 45f,
				StaminaCost = 35f,
				IconItem = "TrophyFenring",
				CastAction = CastLivingFortress,
				Describe = (int lvl) => Loc.F("spell.battle_frenzy.desc", "Immense armor and battle frenzy (+{0}% attack) for {1:0} s", FrenzyAttack(), FortressDuration())
			},
			new SpellDef
			{
				Name = "Shattering Shout",
				UnlockLevel = 35,
				Cooldown = 8f,
				StaminaCost = 20f,
				IconItem = "Club",
				CastAction = CastShatteringShout,
				Describe = (int lvl) => Loc.F("spell.shattering_shout.desc", "A shout that shatters bone ({0} damage in a {1:0} m wave of force)", AdjShoutDamage(lvl), ShoutRadius())
			},
			new SpellDef
			{
				Name = "Horn of War",
				UnlockLevel = 45,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "TankardOdin",
				CastAction = CastGjallarhorn,
				Describe = (int lvl) => Loc.F("spell.horn_of_war.desc", "A devastating war blast ({0} damage, {1:0} m)", AdjHornDamage(lvl), HornRadius())
			}
		};

		public static readonly SpellDef[] ThornweaverSpells = new SpellDef[8]
		{
			new SpellDef
			{
				Name = "Thorn Burst",
				UnlockLevel = 10,
				Cooldown = 6f,
				StaminaCost = 15f,
				IconItem = "Thistle",
				CastAction = CastThornBurst,
				Describe = (int lvl) => Loc.F("spell.thorn_burst.desc", "A burst of thorns erupts in front of you ({0} pierce damage)", AdjThornDamage(lvl))
			},
			new SpellDef
			{
				Name = "Thorn Sap",
				UnlockLevel = 20,
				Cooldown = 12f,
				StaminaCost = 25f,
				IconItem = "Dandelion",
				CastAction = CastRegrowth,
				Describe = (int lvl) => Loc.F("spell.thorn_sap.desc", "Life flows from the thorns: allies recover {0} HP while enemies within 5 m are lashed ({1} pierce)", AdjRegrowthHeal(lvl), AdjThornSapDamage(lvl))
			},
			new SpellDef
			{
				Name = "Forest Blessing",
				UnlockLevel = 30,
				Cooldown = 25f,
				StaminaCost = 25f,
				IconItem = "AncientSeed",
				CastAction = CastForestBlessing,
				Describe = (int lvl) => Loc.F("spell.forest_blessing.desc", "The wild empowers allies within {0:0} m: +{1}% attack and swift stamina for {2:0} s", BlessingRadius(), TalentSystem.Has(LP, "dru_inspiring") ? 25 : 15, ForestBlessingDuration())
			},
			new SpellDef
			{
				Name = "Poison Bloom",
				UnlockLevel = 40,
				Cooldown = 30f,
				StaminaCost = 40f,
				IconItem = "Ooze",
				CastTime = 1.5f,
				CastAction = CastHealingBloom,
				Describe = (int lvl) => Loc.F("spell.poison_bloom.desc", "A venomous circle blooms ({0:0} m, {1:0} s): enemies inside are poisoned for {2} per second", BloomRadius(), BloomDuration(), AdjBloomPoison(lvl))
			},
			new SpellDef
			{
				Name = "Wind's Grace",
				UnlockLevel = 50,
				Cooldown = 30f,
				StaminaCost = 30f,
				IconItem = "Feathers",
				CastAction = CastWindsGrace,
				Describe = (int lvl) => Loc.F("spell.wind_s_grace.desc", "The wind carries allies within {0:0} m: far lighter running for {1:0} s", BlessingRadius(), WindsGraceDuration())
			},
			new SpellDef
			{
				Name = "Grasping Roots",
				UnlockLevel = 60,
				Cooldown = 15f,
				StaminaCost = 35f,
				IconItem = "Root",
				CastAction = CastGraspingRoots,
				Describe = (int lvl) => Loc.F("spell.grasping_roots.desc", "Roots erupt from the earth ({0} pierce + poison damage, {1:0} m) and hurl enemies away", AdjRootsDamage(lvl), RootsRadius())
			},
			new SpellDef
			{
				Name = "Nature's Fury",
				UnlockLevel = 70,
				Cooldown = 30f,
				StaminaCost = 50f,
				IconItem = "TrophyAbomination",
				CastAction = CastForestEmbrace,
				Describe = (int lvl) => Loc.F("spell.nature_s_fury.desc", "Allies within {0:0} m deal +15% pierce and poison damage for {1:0} s", NatureFuryRadius(), NatureFuryDuration())
			},
			new SpellDef
			{
				Name = "Wrath of Yggdrasil",
				UnlockLevel = 80,
				Cooldown = 75f,
				StaminaCost = 80f,
				IconItem = "YggdrasilWood",
				CastTime = 2.5f,
				CastAction = CastWrathOfYggdrasil,
				Describe = (int lvl) => Loc.F("spell.wrath_of_yggdrasil.desc", "The World Tree strikes: enemies take {0} pierce + poison damage from the erupting roots, allies recover {1} HP", AdjYggdrasilDamage(lvl), AdjYggdrasilHeal(lvl))
			}
		};

		private const int BlizzardWaves = 8;

		private const float AbsoluteZeroRadius = 10f;

		private const float GraspDuration = 8f;

		private const int ThorBolts = 12;

		private const float EyeDuration = 10f;

		public const int DomeStyleMage = 0;

		public const int DomeStyleGuardian = 1;

		private static readonly List<Character> FireMinions = new List<Character>();

		private static readonly List<Character> MagmaMinions = new List<Character>();

		private static readonly List<Character> FireArmy = new List<Character>();

		private const string FireImpPrefab = "Surtling";

		private static readonly string[] MagmaPrefabNames = new string[3] { "BlobLava", "Charred_Melee", "Surtling" };

		private static readonly List<Character> SpiritMinions = new List<Character>();

		private static readonly List<Character> Minions = new List<Character>();

		private static readonly List<Character> ArmyMinions = new List<Character>();

		private static readonly Dictionary<string, AscendantPath> AscendantPaths = BuildAscendantPaths();

		private static readonly Dictionary<string, SpellDef[]> ExpandedRosterCache = new Dictionary<string, SpellDef[]>();

		private static readonly Dictionary<PlayerClass, SpellDef> AscensionUltimates = new Dictionary<PlayerClass, SpellDef>();

		private static readonly SpellDef RangerMarkedShot = RangerSpell("Marked Shot", 1, 8f, 12f, "ArrowBronze", 0f, (int lvl) => Loc.F("spell.marked_shot.desc", "A precise shot ({0} pierce)", RangerDamage(13, lvl)), CastMarkedShot);

		private static readonly SpellDef RangerEvasiveShot = RangerSpell("Evasive Shot", 1, 8f, 14f, "BowFineWood", 0f, (int lvl) => Loc.F("spell.evasive_shot.desc", "Loose an arrow ({0} pierce) and leap away", RangerDamage(11, lvl)), CastEvasiveShot);

		private static readonly SpellDef RangerSnareTrap = RangerSpell("Snare Trap", 1, 14f, 15f, "BronzeNails", 0f, (int lvl) => Loc.F("spell.snare_trap.desc", "Set a hidden snare ({0} pierce, arms after 1 s)", RangerDamage(10, lvl)), CastSnareTrap);

		private static readonly SpellDef[] RangerMarksmanshipBaseOnly = new SpellDef[1] { RangerMarkedShot };

		private static readonly SpellDef[] RangerSkirmishingBaseOnly = new SpellDef[1] { RangerEvasiveShot };

		private static readonly SpellDef[] RangerWildernessBaseOnly = new SpellDef[1] { RangerSnareTrap };

		private static readonly SpellDef[] DeadeyeSpells = new SpellDef[5]
		{
			RangerMarkedShot,
			RangerSpell("Aimed Shot", 10, 13f, 20f, "BowHuntsman", 1f, (int lvl) => Loc.F("spell.aimed_shot.desc", "A carefully aimed arrow ({0} pierce)", RangerDamage(25, lvl)), CastAimedShot),
			RangerSpell("Hunter's Mark", 20, 22f, 24f, "TrophySerpent", 0f, (int lvl) => Loc.F("spell.hunter_s_mark.desc", "Mark and strike the nearest prey ({0} pierce)", RangerDamage(30, lvl)), CastHuntersMark),
			RangerSpell("Heartseeker", 40, 30f, 32f, "ArrowSilver", 1.2f, (int lvl) => Loc.F("spell.heartseeker.desc", "A lethal shot that punishes wounded prey ({0} pierce)", RangerDamage(45, lvl)), CastHeartseeker),
			RangerSpell("One Shot", 60, 55f, 48f, "BowSpineSnap", 1.8f, (int lvl) => Loc.F("spell.one_shot.desc", "The hunt ends in one impossible arrow ({0} pierce)", RangerDamage(72, lvl)), CastOneShot)
		};

		private static readonly SpellDef[] ArbalistSpells = new SpellDef[5]
		{
			RangerMarkedShot,
			RangerSpell("Armor Breaker", 10, 14f, 22f, "CrossbowArbalest", 0.8f, (int lvl) => Loc.F("spell.armor_breaker.desc", "A crushing bolt ({0} pierce, heavy knockback)", RangerDamage(28, lvl)), CastArmorBreaker),
			RangerSpell("Pavise", 20, 28f, 25f, "ShieldIronTower", 0f, (int lvl) => Loc.T("spell.pavise.desc", "Brace behind a field shield: greatly increased armor for 12 s"), CastPavise),
			RangerSpell("Siege Bolt", 40, 34f, 36f, "BoltCarapace", 1.3f, (int lvl) => Loc.F("spell.siege_bolt.desc", "A siege projectile detonates through a line ({0} pierce)", RangerDamage(48, lvl)), CastSiegeBolt),
			RangerSpell("Ballista Salvo", 60, 58f, 50f, "CrossbowRipper", 1.5f, (int lvl) => Loc.F("spell.ballista_salvo.desc", "Fire seven heavy bolts in a disciplined salvo ({0} each)", RangerDamage(22, lvl)), CastBallistaSalvo)
		};

		private static readonly SpellDef[] PathfinderSpells = new SpellDef[5]
		{
			RangerEvasiveShot,
			RangerSpell("Quickstep", 10, 10f, 16f, "Feathers", 0f, (int lvl) => Loc.T("spell.quickstep.desc", "Surge forward along a safe path"), CastQuickstep),
			RangerSpell("Rapid Fire", 20, 22f, 26f, "BowFineWood", 0f, (int lvl) => Loc.F("spell.rapid_fire.desc", "Loose five arrows while moving ({0} each)", RangerDamage(13, lvl)), CastRapidFire),
			RangerSpell("Windrunner", 40, 35f, 30f, "MeadStaminaMedium", 0f, (int lvl) => Loc.T("spell.windrunner.desc", "Move almost without stamina cost and recover breath for 12 s"), CastWindrunner),
			RangerSpell("Ghost Trail", 60, 52f, 44f, "TrophyHare", 0f, (int lvl) => Loc.F("spell.ghost_trail.desc", "Become a streak of wind and fire seven arrows ({0} each)", RangerDamage(18, lvl)), CastGhostTrail)
		};

		private static readonly SpellDef[] VolleyMasterSpells = new SpellDef[5]
		{
			RangerEvasiveShot,
			RangerSpell("Split Shot", 10, 12f, 20f, "ArrowBronze", 0f, (int lvl) => Loc.F("spell.split_shot.desc", "Loose five arrows in a wide fan ({0} each)", RangerDamage(10, lvl)), CastSplitShot),
			RangerSpell("Arrow Rain", 20, 25f, 28f, "BowDraugrFang", 0f, (int lvl) => Loc.F("spell.arrow_rain.desc", "Twelve arrows rain over the target ground ({0} each)", RangerDamage(12, lvl)), CastArrowRain),
			RangerSpell("Suppressing Volley", 40, 36f, 38f, "ArrowCarapace", 0f, (int lvl) => Loc.F("spell.suppressing_volley.desc", "Three ordered waves pin down a wide area ({0} per wave)", RangerDamage(18, lvl)), CastSuppressingVolley),
			RangerSpell("Skyfall Barrage", 60, 60f, 52f, "TrophyGjall", 1.2f, (int lvl) => Loc.F("spell.skyfall_barrage.desc", "Twenty-four arrows darken the sky ({0} each)", RangerDamage(19, lvl)), CastSkyfallBarrage)
		};

		private static readonly SpellDef[] TrapperSpells = new SpellDef[5]
		{
			RangerSnareTrap,
			RangerSpell("Caltrops", 10, 18f, 20f, "BronzeNails", 0f, (int lvl) => Loc.F("spell.caltrops.desc", "Scatter caltrops that strike in three pulses ({0} pierce)", RangerDamage(9, lvl)), CastCaltrops),
			RangerSpell("Explosive Trap", 20, 25f, 28f, "BombOoze", 0f, (int lvl) => Loc.F("spell.explosive_trap.desc", "Set an explosive ambush ({0} fire and blunt)", RangerDamage(30, lvl)), CastExplosiveTrap),
			RangerSpell("Venom Mine", 40, 34f, 36f, "Guck", 0f, (int lvl) => Loc.F("spell.venom_mine.desc", "Set a poisonous mine ({0} poison and pierce)", RangerDamage(38, lvl)), CastVenomMine),
			RangerSpell("Grand Hunt", 60, 58f, 50f, "TrophyGoblinShaman", 0f, (int lvl) => Loc.F("spell.grand_hunt.desc", "Seed the hunting ground with five linked traps ({0} each)", RangerDamage(26, lvl)), CastGrandHunt)
		};

		private static readonly SpellDef[] FalconerSpells = new SpellDef[5]
		{
			RangerSnareTrap,
			RangerSpell("Falcon Strike", 10, 13f, 18f, "Feathers", 0f, (int lvl) => Loc.F("spell.falcon_strike.desc", "Your raptor dives onto the chosen prey ({0} pierce)", RangerDamage(22, lvl)), CastFalconStrike),
			RangerSpell("Scout's Mark", 20, 24f, 26f, "TrophyHatchling", 0f, (int lvl) => Loc.F("spell.scout_s_mark.desc", "The raptor marks a target for three coordinated strikes ({0} each)", RangerDamage(14, lvl)), CastScoutsMark),
			RangerSpell("Wingstorm", 40, 36f, 38f, "TrophyDeathsquito", 0f, (int lvl) => Loc.F("spell.wingstorm.desc", "A spiral of feathers tears nearby enemies ({0} per wave)", RangerDamage(20, lvl)), CastWingstorm),
			RangerSpell("Apex Companion", 60, 65f, 50f, "TrophySeeker", 1f, (int lvl) => Loc.T("spell.apex_companion.desc", "Call a temporary great raptor to hunt beside you for 35 s"), CastApexCompanion)
		};

		private static bool AltSpec => GuardianOffense(LP);

		private static Player LP => Player.m_localPlayer;

		public static bool IsChanneling { get; private set; }

		public static float ChannelProgress { get; private set; }

		public static string ChannelSpellName { get; private set; }

		public static float ArmyLifetime => 60f + 15f * (float)(TalentSystem.Rank(LP, "bl_armylong") + TalentSystem.Rank(LP, "bm_calllong") + TalentSystem.Rank(LP, "her_legionlong"));

		public static SpellDef[] GetSpells(Player player)
		{
			if (TrainingHall.TryGetRoster(player, out var roster))
			{
				return roster;
			}
			PlayerClass playerClass = ClassSystem.GetClass(player);
			if (BranchSystem.Has(playerClass))
			{
				return SingleTreeRoster(player);
			}
			if (SpecSystem.HasSpecs(playerClass) && SpecSystem.GetSpec(player) == ClassSpec.Alternative)
			{
				switch (playerClass)
				{
				case PlayerClass.Guardian:
					return VanguardSpells;
				case PlayerClass.Druid:
					return ThornweaverSpells;
				case PlayerClass.Einherjar:
					return ChosenSpells;
				}
			}
			return GetSpells(playerClass);
		}

		private static SpellDef[] SingleTreeRoster(Player player)
		{
			int branch = BranchSystem.GetBranch(player);
			if (branch < 0)
			{
				return new SpellDef[0];
			}
			int subSpec = BranchSystem.GetSubSpec(player);
			PlayerClass playerClass = ClassSystem.GetClass(player);
			SpellDef[] array = playerClass switch
			{
				PlayerClass.Berserker => BerserkerRoster(branch, subSpec), 
				PlayerClass.Necromancer => NecromancerRoster(branch, subSpec), 
				PlayerClass.Druid => DruidRoster(branch, subSpec), 
				PlayerClass.Einherjar => EinherjarSingleRoster(branch, subSpec), 
				PlayerClass.Guardian => GuardianSingleRoster(branch, subSpec), 
				PlayerClass.Ranger => RangerRoster(branch, subSpec), 
				_ => MageRoster(branch, subSpec), 
			};
			if (subSpec < 0)
			{
				return array;
			}
			return ExpandSingleTreeRoster(player, playerClass, branch, subSpec, array);
		}

		private static bool GuardianOffense(Player player)
		{
			if (!SpecSystem.IsAlternative(player))
			{
				if (ClassSystem.GetClass(player) == PlayerClass.Guardian)
				{
					return BranchSystem.GetBranch(player) == 1;
				}
				return false;
			}
			return true;
		}

		private static SpellDef[] GuardianSingleRoster(int branch, int sub)
		{
			return branch switch
			{
				0 => sub switch
				{
					0 => WardenGuardSpells, 
					1 => SentinelSpells, 
					_ => GuardianBulwarkBaseOnly, 
				}, 
				1 => sub switch
				{
					0 => CrusherSpells, 
					1 => WarbringerSpells, 
					_ => GuardianVanguardBaseOnly, 
				}, 
				_ => sub switch
				{
					0 => TemplarSpells, 
					1 => LightbringerSpells, 
					_ => GuardianPaladinBaseOnly, 
				}, 
			};
		}

		private static SpellDef[] EinherjarSingleRoster(int branch, int sub)
		{
			return branch switch
			{
				0 => sub switch
				{
					0 => ThundererSpells, 
					1 => StormheraldSpells, 
					_ => EinherStormBaseOnly, 
				}, 
				1 => sub switch
				{
					0 => SpearmasterSpells, 
					1 => ValkyrieKnightSpells, 
					_ => EinherSpearBaseOn