-- Path of Building
--
-- Active Dexterity skill gems
-- Skill data (c) Grinding Gear Games
--
local skills, mod, flag, skill = ...

#skill AlchemistsMark
#flags spell curse mark area duration
	statMap = {
		["alchemists_mark_igniter_creates_burning_ground_%_ignite_damage"] = {
			mod("IgniteDpsAsBurningGround", "MAX", nil, 0, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
		["alchemists_mark_poisoner_creates_caustic_ground_%_poison_damage"] = {
			mod("PoisonDpsAsCausticGround", "MAX", nil, 0, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
		["alchemists_mark_grant_attacker_x_flask_charges_when_hit_once_per_3s"] = {
			-- Uncomment below and delete subsequent line when we get "per hit" flask charge generation working
			-- mod("FlaskChargesGenerated", "BASE", nil, 0, KeywordFlag.Hit, { type = "ActorCondition", actor = "enemy", var = "Cursed" }),
			-- Delete this line if you uncomment the one above: this assume we are hitting the marked target as often as we can
			mod("FlaskChargesGenerated", "BASE", nil),
			div = 3,
		},
	},
#baseMod skill("debuff", true)
#baseMod skill("radius", 20)
#mods

#skill Ambush
#flags spell movement duration travel
	statMap = {
		["ambush_additional_critical_strike_chance_permyriad"] = {
			mod("CritChance", "BASE", nil, ModFlag.Melee, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Ambush" }),
			div = 100,
		},
		["vanishing_ambush_critical_strike_multiplier_+"] = {
			mod("CritMultiplier", "BASE", nil, ModFlag.Melee, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Ambush" }),
		},
		-- not excluding Exert for Two-Handed weapons, to simulate a potential weapon swap for skills with a duration ( Rage Vortex )
	},
#mods

#skill AnimateWeapon
#flags spell minion duration
	minionHasItemSet = true,
	minionUses = {
		["Weapon 1"] = true,
	},
	minionList = {
		"AnimatedWeapon",
	},
	statMap = {
		["attack_minimum_added_physical_damage"] = {
			mod("MinionModifier", "LIST", { mod = mod("PhysicalMin", "BASE", nil, 0, KeywordFlag.Attack) }),
		},
		["attack_maximum_added_physical_damage"] = {
			mod("MinionModifier", "LIST", { mod = mod("PhysicalMax", "BASE", nil, 0, KeywordFlag.Attack) }),
		},
		["attack_minimum_added_physical_damage_for_ethereal_blades"] = {
			mod("MinionModifier", "LIST", { mod = mod("PhysicalMin", "BASE", nil, 0, KeywordFlag.Attack, { type = "ActorCondition", actor = "parent", var = "AnimatingLingeringBlades" }) }),
		},
		["attack_maximum_added_physical_damage_for_ethereal_blades"] = {
			mod("MinionModifier", "LIST", { mod = mod("PhysicalMax", "BASE", nil, 0, KeywordFlag.Attack, { type = "ActorCondition", actor = "parent", var = "AnimatingLingeringBlades" }) }),
		},
		["base_number_of_animated_weapons_allowed"] = {
			mod("Multiplier:AnimatedWeapon", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true })
		},
	},
#mods

#skill AnimateWeaponAltX
#flags spell minion duration
	minionHasItemSet = true,
	minionUses = {
		["Weapon 1"] = true,
	},
	minionList = {
		"AnimatedWeapon",
	},
	statMap = {
		["base_number_of_animated_weapons_allowed"] = {
			mod("Multiplier:AnimatedWeapon", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true })
		},
	},
#mods

#skill AnimateWeaponAltY
#flags spell minion duration
	minionHasItemSet = true,
	minionUses = {
		["Weapon 1"] = true,
	},
	minionList = {
		"AnimatedWeapon",
	},
	statMap = {
		["attack_minimum_added_physical_damage"] = {
			mod("MinionModifier", "LIST", { mod = mod("PhysicalMin", "BASE", nil, 0, KeywordFlag.Attack) }),
		},
		["attack_maximum_added_physical_damage"] = {
			mod("MinionModifier", "LIST", { mod = mod("PhysicalMax", "BASE", nil, 0, KeywordFlag.Attack) }),
		},
		["attack_minimum_added_physical_damage_for_ethereal_blades"] = {
			mod("MinionModifier", "LIST", { mod = mod("PhysicalMin", "BASE", nil, 0, KeywordFlag.Attack, { type = "ActorCondition", actor = "parent", var = "AnimatingLingeringBlades" }) }),
		},
		["attack_maximum_added_physical_damage_for_ethereal_blades"] = {
			mod("MinionModifier", "LIST", { mod = mod("PhysicalMax", "BASE", nil, 0, KeywordFlag.Attack, { type = "ActorCondition", actor = "parent", var = "AnimatingLingeringBlades" }) }),
		},
		["base_number_of_animated_weapons_allowed"] = {
			mod("Multiplier:AnimatedWeapon", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true })
		},
	},
#mods

#skill VaalAnimateWeapon
#flags spell minion duration
	minionHasItemSet = true,
	minionUses = {
		["Weapon 1"] = true,
	},
	minionList = {
		"AnimatedWeapon",
	},
	statMap = {
		["base_movement_velocity_+%"] = {
			mod("MinionModifier", "LIST", { mod = mod("MovementSpeed", "INC", nil) }),
		},
		["base_number_of_animated_weapons_allowed"] = {
			mod("Multiplier:VaalAnimatedWeapon", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true })
		},
	},
#mods

#skill ArcticArmour
#flags spell duration
	statMap = {
		["new_arctic_armour_physical_damage_taken_when_hit_+%_final"] = {
			mod("PhysicalDamageTakenWhenHit", "MORE", nil, 0, 0, { type = "Condition", var = "Stationary" }, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["new_arctic_armour_fire_damage_taken_when_hit_+%_final"] = {
			mod("FireDamageTakenWhenHit", "MORE", nil, 0, 0, { type = "Condition", var = "Stationary" }, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["base_immune_to_freeze"] = {
			flag("FreezeImmune", { type = "GlobalEffect", effectType = "Buff"}),
		},
	},
#mods

#skill VaalArcticArmour
#flags spell duration
	statMap = {
		["vaal_arctic_armour_damage_taken_+%_final_from_hits"] = {
			mod("VaalArcticArmourMitigation", "MORE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true }),
		},
		["vaal_arctic_armour_number_of_hits_absorbed"] = {
			mod("VaalArcticArmourMaxHits", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true }),
		},
		["base_mana_regeneration_rate_per_minute"] = {
			mod("ManaRegen", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
			div = 60,
		},
		["base_energy_shield_regeneration_rate_per_minute"] = {
			mod("EnergyShieldRegen", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
			div = 60,
		},
	},
#mods

#skill ArtilleryBallista
#flags attack projectile area totem ballista
#baseMod flag("OneShotProj")
#mods

#skill ArtilleryBallistaAltX
#flags attack projectile area totem ballista
#baseMod flag("OneShotProj")
#mods

#skill ArtilleryBallistaAltY
#flags attack projectile area totem ballista
#baseMod flag("OneShotProj")
#mods

#skill Barrage
#flags attack projectile
	parts = {
		{
			name = "1 Projectile",
		},
		{
			name = "All Projectiles",
		},
	},
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.dpsMultiplier = output.ProjectileCount
		end
	end,
	statMap = {
		["projectiles_barrage"] = {
		},
	},
#mods

#skill BarrageAltX
#flags attack projectile
	parts = {
		{
			name = "1 Projectile",
		},
		{
			name = "All Projectiles",
		},
	},
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.dpsMultiplier = output.ProjectileCount
		end
	end,
	statMap = {
		["projectiles_barrage"] = {
		},
	},
#mods

#skill BearTrap
#flags cast trap duration
	statMap = {
		["bear_trap_damage_taken_+%_from_traps_and_mines"] = {
			mod("TrapMineDamageTaken", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Debuff" }),
		},
	},
#mods

#skill BearTrapAltX
#flags cast trap duration
#mods

#skill BladeBlast
#flags spell area
	parts = {
		{
			name = "Blade Hits Per Cast",
			stages = true,
		},
		{
			name = "Blade Hits Per Sec",
			stages = true,
		},
	},
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.dpsMultiplier = (activeSkill.skillData.dpsMultiplier or 1) * activeSkill.skillData.dpsBaseMultiplier
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.hitTimeOverride = 1
		end
	end,
#baseMod mod("Multiplier:BladeBlastMaxStages", "BASE", 900, 0, 0)
#baseMod skill("dpsBaseMultiplier", 1, { type = "Multiplier", var = "BladeBlastStage" })
#mods

#skill BladeBlastAltX
#flags spell area
	parts = {
		{
			name = "Blade Hits Per Cast",
			stages = true,
		},
		{
			name = "Blade Hits Per Sec",
			stages = true,
		},
	},
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.dpsMultiplier = (activeSkill.skillData.dpsMultiplier or 1) * activeSkill.skillData.dpsBaseMultiplier
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.hitTimeOverride = 1
		end
	end,
	statMap = {
		["blade_burst_area_of_effect_+%_final_per_blade_vortex_blade_detonated"] = {
			mod("AreaOfEffect", "MORE", nil, 0, 0, { type = "Multiplier", var = "BladeBlastofUnloadingStage" })
		},
		["blade_vortex_damage_+%_per_blade_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "Multiplier", var = "BladeBlastofUnloadingStage" })
		},
		["damage_per_blade_vortex_blade_description_mode"] = {},
	},
#baseMod mod("Multiplier:BladeBlastofUnloadingMaxStages", "BASE", 10, 0, 0)
#baseMod skill("dpsBaseMultiplier", 1, { type = "Multiplier", var = "BladeBlastofUnloadingStage" })
#mods

#skill BladeBlastAltY
#flags spell area
	statMap = {
		["gain_%_of_base_dagger_damage_as_added_spell_damage"] = {
			skill("gainPercentBaseDaggerDamage", nil),
		},
	},
#mods

#skill BladeTrap
#flags attack area trap
#mods

#skill BladeTrapAltX
#flags attack area trap
#mods

#skill BladeTrapAltY
#flags attack area trap
	statMap = {
		["quality_display_active_skill_bleed_damage_final_is_gem"] = {
			--Display only
		},
	},
#mods

#skill BladeFlurry
#flags attack melee area
	parts = {
		{
			name = "Channelling",
			stages = true,
		},
		{
			name = "Channel & Release",
			stages = true,
		},
	},
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 and activeSkill.skillData.numStages > 0 then
			local numStages = activeSkill.skillData.numStages
			local channelMulti = 0
			for i = 1, numStages do
				channelMulti = channelMulti + (0.8 + (0.2 * i))
			end
			channelMulti = channelMulti / (0.8 + (0.2 * numStages))
			activeSkill.skillData.dpsMultiplier = channelMulti / numStages + 1
		end
	end,
	statMap = {
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["charged_attack_damage_per_stack_+%_final"] = {
			mod("Damage", "MORE", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "Multiplier", var = "BladeFlurryStage" }),
		},
		["display_max_charged_attack_stats"] = {
			mod("Multiplier:BladeFlurryMaxStages", "BASE", nil),
		},
		["blade_flurry_damage_+%_final_while_at_max_stages"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "MultiplierThreshold", var = "BladeFlurryStage", thresholdVar = "BladeFlurryMaxStages" }),
		},
		["quality_display_charged_attack_is_gem"] = {
			--Display only
		},
	},
#baseMod skill("numStages", 1, { type = "Multiplier", var = "BladeFlurryStage" })
#baseMod skill("stackMultiplier", 2, { type = "SkillPart", skillPart = 2 })
#baseMod skill("radius", 14)
#mods

#skill BladeFlurryAltX
#flags attack melee area
	parts = {
		{
			name = "Channelling",
			stages = true,
		},
		{
			name = "Channel & Release",
			stages = true,
		},
	},
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 and activeSkill.skillData.numStages > 0 then
			local numStages = activeSkill.skillData.numStages
			local channelMulti = 0
			for i = 1, numStages do
				channelMulti = channelMulti + (0.8 + (0.2 * i))
			end
			channelMulti = channelMulti / (0.8 + (0.2 * numStages))
			activeSkill.skillData.dpsMultiplier = channelMulti / numStages + 1
		end
	end,
	statMap = {
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["blade_flurry_critical_strike_chance_per_stage_+%_final"] = {
			mod("CritChance", "MORE", nil, 0, 0, { type = "Multiplier", var = "BladeFlurryofIncisionStage" }),
		},
		["blade_flurry_critical_strike_multiplier_+_while_at_max_stages"] = {
			mod("CritMultiplier", "BASE", nil, 0, 0, { type = "MultiplierThreshold", var = "BladeFlurryofIncisionStage", thresholdVar = "BladeFlurryofIncisionMaxStages" }),
		},
		["display_max_charged_attack_stats"] = {
			mod("Multiplier:BladeFlurryofIncisionMaxStages", "BASE", nil),
		},
		["quality_display_charged_attack_is_gem"] = {
			--Display only
		},
	},
#baseMod skill("numStages", 1, { type = "Multiplier", var = "BladeFlurryofIncisionStage" })
#baseMod skill("stackMultiplier", 2, { type = "SkillPart", skillPart = 2 })
#baseMod skill("radius", 14)
#mods

#skill VaalBladeFlurry
#flags attack melee area
	statMap = {
		["vaal_charged_attack_damage_taken_+%_final"] = {
			mod("DamageTaken", "MORE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
	},
#mods

#skill BladeVortex
#flags spell area duration
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.hitTimeOverride = activeSkill.skillData.hitFrequency / (1 + activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "Multiplier:BladeVortexBlade") * activeSkill.skillData.hitFrequencyPerBlade)
	end,
	parts = {
		{
			name = "0 Blades",
		},
		{
			name = "5 Blades",
		},
		{
			name = "10 Blades",
		},
	},
	statMap = {
		["blade_vortex_damage_+%_per_blade_final"] = {
			mod("Damage", "MORE", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "Multiplier", var = "BladeVortexBlade" }),
		},
		["blade_vortex_ailment_damage_+%_per_blade_final"] = {
			mod("Damage", "MORE", nil, 0, KeywordFlag.Ailment, { type = "Multiplier", var = "BladeVortexBlade" }),
		},
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["maximum_number_of_spinning_blades"] = {
			mod("Multiplier:BladeVortexMaxStages", "BASE", nil),
		},
		["blade_vortex_hit_rate_+%_per_blade"] = {
			skill("hitFrequencyPerBlade", nil),
			div = 100,
		},
		["quality_display_blade_vortex_is_gem"] = {
			--Display only
		},
	},
#baseMod skill("radius", 15)
#baseMod skill("hitFrequency", 0.6)
#baseMod mod("Multiplier:BladeVortexBlade", "BASE", 5, 0, 0, { type = "SkillPart", skillPart = 2 })
#baseMod mod("Multiplier:BladeVortexBlade", "BASE", 10, 0, 0, { type = "SkillPart", skillPart = 3 })
#baseMod flag("Condition:HaveBladeVortex")
#mods

#skill BladeVortexAltX
#flags spell area duration
	statMap = {
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["quality_display_blade_vortex_is_gem"] = {
			--Display only
		},
	},
#baseMod skill("radius", 15)
#baseMod skill("hitTimeOverride", 0.6)
#baseMod flag("Condition:HaveBladeVortex")
#mods

#skill VaalBladeVortex
#flags spell area duration
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.hitTimeOverride = activeSkill.skillData.hitFrequency / (1 + activeSkill.skillData.VaalBladeVortexBlade * (activeSkill.skillData.hitFrequencyPerBlade or 0))
	end,
	statMap = {
		["base_blade_vortex_hit_rate_ms"] = {
			skill("hitFrequency", nil),
			div = 1000,
		},
		["blade_vortex_hit_rate_+%_per_blade"] = {
			skill("hitFrequencyPerBlade", nil),
			div = 100,
		},
		["vaal_blade_vortex_has_10_spinning_blades"] = {
		},
	},
#baseMod skill("radius", 15)
#baseMod skill("VaalBladeVortexBlade", 10)
#mods

#skill Bladefall
#flags spell area
	statMap = {
		["quality_display_bladefall_is_gem"] = {
			--Display only
		},
	},
#baseMod skill("radius", 44)
#baseMod skill("radiusLabel", "Volley Width:")
#baseMod skill("radiusSecondary", 12)
#baseMod skill("radiusSecondaryLabel", "Volley Length:")
#mods

#skill BladefallAltX
#flags spell area
	statMap = {
		["bladefall_damage_per_stage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "Multiplier", var = "BladefallofVolleysStage" }),
		},
		["bladefall_critical_strike_chance_+%_per_stage"] = {
			mod("CritChance", "INC", nil, 0, 0, { type = "Multiplier", var = "BladefallofVolleysStage" }),
		},
		["bladefall_number_of_volleys"] = {
			mod("Multiplier:BladefallofVolleysMaxStages", "BASE", nil),
		},
		["quality_display_bladefall_is_gem"] = {
			--Display only
		},
	},
#mods

#skill BladefallAltY
#flags spell area
	statMap = {
		["quality_display_bladefall_is_gem"] = {
			--Display only
		},
	},
#mods

#skill BladefallAltZ
#flags spell area
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.hitTimeOverride = activeSkill.skillData.hitFrequency / (1 + activeSkill.skillData.incVolleyFrequency / 100)
	end,
	statMap = {
		["quality_display_bladefall_is_gem"] = {
			--Display only
		},
		["bladefall_base_volley_frequency_ms"] = {
			skill("hitFrequency", nil),
			div = 1000,
		},
		["bladefall_volley_frequency_+%_per_100_maximum_mana"] = {
			skill("incVolleyFrequency", nil, { type = "PerStat", stat = "Mana", div = 100 }),
		},
	},
#mods

#skill BlastRain
#flags attack projectile area
	parts = {
		{
			name = "1 Projectile",
		},
		{
			name = "All Projectiles",
		},
	},
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.dpsMultiplier = output.ProjectileCount
		end
	end,
#baseMod skill("radius", 24)
#baseMod flag("OneShotProj")
#mods

#skill BlastRainAltX
#flags attack projectile area
#mods

#skill BlinkArrow
#flags attack projectile minion duration
	minionList = {
		"ArrowClone",
	},
#baseMod skill("minionUseBowAndQuiver", true)
#mods

#skill BlinkArrowAltX
#flags attack projectile minion duration
	minionList = {
		"ArrowCloneRoA",
	},
#baseMod skill("minionUseBowAndQuiver", true)
#mods

#skill BlinkArrowAltY
#flags attack projectile minion duration
	minionList = {
		"ArrowCloneEle",
	},
#baseMod skill("minionUseBowAndQuiver", true)
#mods

#skill BloodRage
#flags spell duration
	statMap = {
		["base_physical_damage_%_of_maximum_life_to_deal_per_minute"] = {
			mod("PhysicalDegen", "BASE", nil, 0, 0, { type = "PerStat", stat = "Life", div = 1}, { type = "GlobalEffect", effectType = "Buff" }),
			div = 6000,
		},
		["base_physical_damage_%_of_maximum_energy_shield_to_deal_per_minute"] = {
			mod("PhysicalDegen", "BASE", nil, 0, 0, { type = "PerStat", stat = "EnergyShield", div = 1}, { type = "GlobalEffect", effectType = "Buff" }),
			div = 6000,
		},
		["attack_speed_+%_granted_from_skill"] = {
			mod("Speed", "INC", nil, ModFlag.Attack, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["life_leech_from_physical_attack_damage_permyriad"] = {
			mod("PhysicalDamageLifeLeech", "BASE", nil, ModFlag.Attack, 0, { type = "GlobalEffect", effectType = "Buff" }),
			div = 100,
		},
	},
#baseMod skill("thisIsNotABuff", true)
#mods

#skill BurningArrow
#flags attack projectile
#mods

#skill BurningArrowAltX
#flags attack projectile
	statMap = {
		["added_fire_damage_to_attacks_equal_to_%_maximum_life"] = {
			mod("FireMin", "BASE", nil, ModFlag.Attack, 0, { type = "PercentStat", stat = "Life", percent = 1 }),
			mod("FireMax", "BASE", nil, ModFlag.Attack, 0, { type = "PercentStat", stat = "Life", percent = 1 }),
		},
	},
#mods

#skill VaalBurningArrow
#flags attack projectile area vaal
#baseMod skill("radius", 16)
#mods

#skill CausticArrow
#flags attack projectile area duration
	statMap = {
		["caustic_arrow_explode_on_hit_base_area_of_effect_radius"] = {
			skill("radius", nil),
		},
	},
#baseMod skill("radiusSecondary", 20)
#baseMod skill("radiusLabel", "AoE Explosion:")
#baseMod skill("radiusSecondaryLabel", "Caustic Ground:")
#baseMod skill("dotIsArea", true)
#baseMod flag("dotIsCausticGround")
#mods

#skill CausticArrowAltX
#flags attack projectile area
	statMap = {
		["caustic_arrow_explode_on_hit_base_area_of_effect_radius"] = {
			skill("radius", nil),
		},
	},
#baseMod skill("radiusLabel", "AoE Explosion:")
#mods

#skill VaalCausticArrow
#flags attack projectile area duration
#baseMod skill("radius", 12)
#baseMod skill("radiusSecondary", 20)
#baseMod skill("radiusLabel", "AoE Explosion:")
#baseMod skill("radiusSecondaryLabel", "Caustic Ground:")
#baseMod skill("dotIsArea", true)
#baseMod flag("dotIsCausticGround")
#mods

#skill CallOfSteel
#flags area
#mods

#skill ChargedDash
#flags attack melee area
	parts = {
		{
			name = "Channelling, No Stages",
		},
		{
			name = "Channelling, Max Stages",
		},
		{
			name = "Release",
			stages = true,
		},
	},
	preDamageFunc = function(activeSkill, output)
		   if activeSkill.skillPart == 3 then
			   local finalWaveDamageModifier = activeSkill.skillModList:Sum("INC", activeSkill.skillCfg, "chargedDashFinalDamageModifier")
			   activeSkill.skillModList:NewMod("Damage", "MORE", finalWaveDamageModifier, "Skill:ChargedDash", ModFlag.Attack, { type = "Release Damage", skillPart = 3 })
		   end
	end,
	statMap = {
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["charged_dash_damage_+%_final"] = {
			mod("chargedDashFinalDamageModifier", "INC", nil, 0, 0, { type = "SkillPart", skillPart = 3 }),
		},
		["charged_dash_damage_+%_final_per_stack"] = {
			mod("chargedDashFinalDamageModifier", "INC", nil, 0, 0, { type = "Multiplier", var = "ChargedDashStage" }, { type = "SkillPart", skillPart = 3 }),
		},
		["charged_dash_channelling_damage_at_full_stacks_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
		},
	},
#baseMod skill("radius", 14)
#baseMod skill("radiusLabel", "Start of Dash:")
#baseMod skill("radiusSecondary", 26)
#baseMod skill("radiusSecondaryLabel", "End of Dash:")
#baseMod skill("hitTimeMultiplier", 2, { type = "Skill", skillPartList = { 1, 2 } })
#baseMod mod("Multiplier:ChargedDashMaxStages", "BASE", 15)
#baseMod skill("showAverage", true, { type = "SkillPart", skillPart = 3 })
#mods

#skill CobraLash
#flags attack projectile
	statMap = {
		["cobra_lash_hit_and_ailment_damage_+%_final_for_each_remaining_chain"] = {
			mod("Damage", "MORE", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "PerStat", stat = "ChainRemaining" }, { type = "SkillType", skillType = SkillType.Projectile })
		},
	},
#mods

#skill Conflagration
#flags attack projectile area duration
	parts = {
		{
			name = "Projectile",
		},
		{
			name = "Explosion",
		},
	},
	statMap = {
		["napalm_arrow_detonation_hit_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "SkillPart", skillPart = 2 } )
		},
		["base_fire_damage_to_deal_per_minute"] = {
			skill("FireDot", nil, { type = "SkillPart", skillPart = 2 }),
			div = 60,
		},
	},
#mods

#skill Cremation
#flags spell projectile area
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 1 then
			activeSkill.skillData.hitTimeOverride = activeSkill.skillData.cremationFireRate / (1 + (activeSkill.skillData.cremationFireRateIncrease or 0))
		end
	end,
	parts = {
		{
			name = "Spell",
			spell = true,
			cast = false,
		},
		{
			name = "Corpse Explosion",
			spell = false,
			cast =  true,
			projectile = false,
		},
	},
	statMap = {
		["cremation_base_fires_projectile_every_x_ms"] = {
			skill("cremationFireRate", nil),
			div = 1000
		},
		["cremation_fires_projectiles_faster_+%_final"] = {
			skill("cremationFireRateIncrease", nil),
			div = 100
		},
		["base_skill_show_average_damage_instead_of_dps"] = {
		}
	},
#baseMod skill("radius", 15)
#baseMod skill("explodeCorpse", true, { type = "SkillPart", skillPart = 2 })
#mods

#skill CremationAltX
#flags spell projectile area
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 1 then
			activeSkill.skillData.hitTimeOverride = activeSkill.skillData.cremationFireRate / (1 + (activeSkill.skillData.cremationFireRateIncrease or 0))
		end
	end,
	parts = {
		{
			name = "Spell",
			spell = true,
			cast = false,
		},
		{
			name = "Corpse Explosion",
			spell = false,
			cast =  true,
			projectile = false,
		},
	},
	statMap = {
		["cremation_base_fires_projectile_every_x_ms"] = {
			skill("cremationFireRate", nil),
			div = 1000
		},
		["cremation_fires_projectiles_faster_+%_final"] = {
			skill("cremationFireRateIncrease", nil),
			div = 100
		},
		["base_skill_show_average_damage_instead_of_dps"] = {
		}
	},
#baseMod skill("radius", 15)
#baseMod skill("explodeCorpse", true, { type = "SkillPart", skillPart = 2 })
#mods

#skill CremationAltY
#flags spell projectile area
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.hitTimeOverride = activeSkill.skillData.cremationFireRate / (1 + (activeSkill.skillData.cremationFireRateIncrease or 0))
	end,
	statMap = {
		["cremation_base_fires_projectile_every_x_ms"] = {
			skill("cremationFireRate", nil),
			div = 1000
		},
		["cremation_fires_projectiles_faster_+%_final"] = {
			skill("cremationFireRateIncrease", nil),
			div = 100
		},
		["base_skill_show_average_damage_instead_of_dps"] = {
		}
	},
#baseMod skill("radius", 15)
#mods

#skill Cyclone
#flags attack melee area
	initialFunc = function(activeSkill, output)
		local range = 0
		if activeSkill.skillFlags.weapon1Attack and activeSkill.actor.weaponData1.range then
			local weapon1RangeBonus = activeSkill.skillModList:Sum("BASE", activeSkill.weapon1Cfg, "MeleeWeaponRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.weapon1Cfg, "MeleeWeaponRangeMetre") + activeSkill.actor.weaponData1.rangeBonus
			if activeSkill.skillFlags.weapon2Attack and activeSkill.actor.weaponData2.range then -- dual wield average
				range = (weapon1RangeBonus + activeSkill.skillModList:Sum("BASE", activeSkill.weapon2Cfg, "MeleeWeaponRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.weapon2Cfg, "MeleeWeaponRangeMetre") + activeSkill.actor.weaponData2.rangeBonus) / 2
			else -- primary hand attack
				range = weapon1RangeBonus
			end
		else -- unarmed
			range = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "UnarmedRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "UnarmedRangeMetre")
		end
		activeSkill.skillModList:NewMod("Multiplier:AdditionalMeleeRange", "BASE", range, "Skill:Cyclone")
	end,
	statMap = {
		["cyclone_area_of_effect_+%_per_additional_melee_range"] = {
			mod("AreaOfEffect", "INC", nil, 0, 0, { type = "Multiplier", var = "AdditionalMeleeRange"}),
		},
		["cyclone_movement_speed_+%_final"] = {
			mod("MovementSpeed", "MORE", nil, 0, 0, { type = "Condition", var = "ChannellingCyclone"}, { type = "GlobalEffect", effectType = "Buff", unscalable = true }),
		},
	},
#baseMod skill("radius", 16)
#mods

#skill CycloneAltX
#flags attack melee area
	initialFunc = function(activeSkill, output)
		local range = 0
		if activeSkill.skillFlags.weapon1Attack and activeSkill.actor.weaponData1.range then
			local weapon1RangeBonus = activeSkill.skillModList:Sum("BASE", activeSkill.weapon1Cfg, "MeleeWeaponRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.weapon1Cfg, "MeleeWeaponRangeMetre") + activeSkill.actor.weaponData1.rangeBonus
			if activeSkill.skillFlags.weapon2Attack and activeSkill.actor.weaponData2.range then -- dual wield average
				range = (weapon1RangeBonus + activeSkill.skillModList:Sum("BASE", activeSkill.weapon2Cfg, "MeleeWeaponRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.weapon2Cfg, "MeleeWeaponRangeMetre") + activeSkill.actor.weaponData2.rangeBonus) / 2
			else -- primary hand attack
				range = weapon1RangeBonus
			end
		else -- unarmed
			range = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "UnarmedRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "UnarmedRangeMetre")
		end
		activeSkill.skillModList:NewMod("Multiplier:AdditionalMeleeRange", "BASE", range, "Skill:CycloneAltX")
	end,
	statMap = {
		["cyclone_max_number_of_stages"] = {
			mod("Multiplier:CycloneofTumultMaxStages", "BASE", nil),
		},
		["cyclone_area_of_effect_+%_per_additional_melee_range"] = {
			mod("AreaOfEffect", "INC", nil, 0, 0, { type = "Multiplier", var = "AdditionalMeleeRange"}),
		},
		--["cyclone_movement_speed_+%_final_per_stage"] = {
			--mod("MovementSpeed", "MORE", nil, 0, 0, { type = "Multiplier", var = "CycloneofTumultStage" }, { type = "Condition", var = "ChannellingCyclone" }, { type = "GlobalEffect", effectType = "Buff", unscalable = true }),
		--},
		["cyclone_attack_speed_+%_final_per_stage"] = {
			mod("Speed", "MORE", nil, ModFlag.Attack, 0, { type = "Multiplier", var = "CycloneofTumultStage" }),
		},
		["cyclone_melee_weapon_range_+_per_stage"] = {
			skill("radiusExtra", nil, { type = "Multiplier", var = "CycloneofTumultStage" }),
		},
	},
#baseMod skill("radius", 11)
#mods

#skill VaalCyclone
#flags attack melee area duration vaal
	statMap = {
		["cyclone_area_of_effect_+%_per_additional_melee_range"] = {
			mod("AreaOfEffect", "INC", nil, 0, 0, { type = "Multiplier", var = "AdditionalMeleeRange"}),
		},
	},
	initialFunc = function(activeSkill, output)
		local range = 0
		if activeSkill.skillFlags.weapon1Attack and activeSkill.actor.weaponData1.range then
			local weapon1RangeBonus = activeSkill.skillModList:Sum("BASE", activeSkill.weapon1Cfg, "MeleeWeaponRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.weapon1Cfg, "MeleeWeaponRangeMetre") + activeSkill.actor.weaponData1.rangeBonus
			if activeSkill.skillFlags.weapon2Attack and activeSkill.actor.weaponData2.range then -- dual wield average
				range = (weapon1RangeBonus + activeSkill.skillModList:Sum("BASE", activeSkill.weapon2Cfg, "MeleeWeaponRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.weapon2Cfg, "MeleeWeaponRangeMetre") + activeSkill.actor.weaponData2.rangeBonus) / 2
			else -- primary hand attack
				range = weapon1RangeBonus
			end
		else -- unarmed
			range = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "UnarmedRange") + 10 * activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "UnarmedRangeMetre")
		end
		activeSkill.skillModList:NewMod("Multiplier:AdditionalMeleeRange", "BASE", range, "Skill:Cyclone")
	end,
#baseMod skill("radius", 24)
#mods

#skill Dash
#flags spell
#mods

#skill Desecrate
#flags spell area duration
#baseMod skill("dotIsArea", true)
#baseMod skill("radius", 12)
#mods

#skill DetonateDead
#flags spell area
	parts = {
		{
			name = "Spell",
			spell = true,
			cast = false,
		},
		{
			name = "Corpse Explosion",
			spell = false,
			cast =  true,
		},
	},
	statMap = {
		["spell_minimum_base_fire_damage"] = {
			skill("FireMin", nil, { type = "SkillPart", skillPart = 1 }),
		},
		["spell_maximum_base_fire_damage"] = {
			skill("FireMax", nil, { type = "SkillPart", skillPart = 1 }),
		},
	},
#baseMod skill("explodeCorpse", true, { type = "SkillPart", skillPart = 2 })
#mods

#skill DetonateDeadAltX
#flags area
	#baseMod skill("explodeCorpse", true)
#mods

#skill DetonateDeadAltY
#flags spell area
	parts = {
		{
			name = "Spell",
			spell = true,
			cast = false,
		},
		{
			name = "Corpse Explosion",
			spell = false,
			cast =  true,
		},
	},
	statMap = {
		["spell_minimum_base_fire_damage"] = {
			skill("FireMin", nil, { type = "SkillPart", skillPart = 1 }),
		},
		["spell_maximum_base_fire_damage"] = {
			skill("FireMax", nil, { type = "SkillPart", skillPart = 1 }),
		},
	},
#baseMod skill("explodeCorpse", true, { type = "SkillPart", skillPart = 2 })
#mods

#skill VaalDetonateDead
#flags cast area
	parts = {
		{
			name = "Spell",
			spell = true,
			cast = false,
		},
		{
			name = "Corpse Explosion",
			spell = false,
			cast =  true,
		},
	},
	statMap = {
		["spell_minimum_base_fire_damage"] = {
			skill("FireMin", nil, { type = "SkillPart", skillPart = 1 }),
		},
		["spell_maximum_base_fire_damage"] = {
			skill("FireMax", nil, { type = "SkillPart", skillPart = 1 }),
		},
	},
#baseMod skill("explodeCorpse", true, { type = "SkillPart", skillPart = 2 })
#mods

#skill DoubleStrike
#flags attack melee
#baseMod skill("dpsMultiplier", 2)
#baseMod mod("PvpTvalueMultiplier", "MORE", -50)
#mods

#skill DoubleStrikeAltX
#flags attack melee
#baseMod skill("dpsMultiplier", 2)
#baseMod mod("PvpTvalueMultiplier", "MORE", -50)
#mods

#skill DoubleStrikeAltY
#flags attack melee
	statMap = {
		["double_strike_max_stages"] = {
			mod("Multiplier:DoubleStrikeofMomentumMaxStages", "BASE", nil),
		},
		["double_strike_attack_speed_+%_final_per_stage"] = {
			mod("Speed", "MORE", nil, ModFlag.Attack, 0, { type = "Multiplier", var = "DoubleStrikeofMomentumStage" }),
		},
	},
#baseMod skill("dpsMultiplier", 2)
#baseMod mod("PvpTvalueMultiplier", "MORE", -50)
#mods

#skill VaalDoubleStrike
#flags attack melee duration vaal
#mods

#skill DualStrike
#flags attack melee
	statMap = {
		["dual_strike_critical_strike_chance_+%_final_against_enemies_on_full_life"] = {
			mod("CritChance", "MORE", nil, 0, 0, { type = "ActorCondition", actor = "enemy", var = "FullLife" })
		},
		["dual_strike_damage_+%_final_against_enemies_on_full_life"] = {
			mod("Damage", "MORE", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "ActorCondition", actor = "enemy", var = "FullLife" })
		},
		["quality_display_dual_strike_is_gem"] = {
			-- Display only
		},
	},
#mods

#skill DualStrikeAltX
#flags attack melee
	statMap = {
		["dual_strike_off_hand_weapon_determines_attack_time"] = {
			flag("UseOffhandAttackSpeed"),
		},
	},
#mods

#skill ElementalHit
#flags attack melee projectile
	parts = {
		{
			name = "Fire Attack",
			area = false,
		},
		{
			name = "Fire AoE",
			area = true,
		},
		{
			name = "Cold Attack",
			area = false,
		},
		{
			name = "Cold AoE",
			area = true,
		},
		{
			name = "Lightning Attack",
			area = false,
		},
		{
			name = "Lightning AoE",
			area = true,
		},
	},
	statMap = {
		["elemental_hit_damage_+%_final_per_enemy_elemental_ailment"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "Multiplier", var = "ElementalHitAilmentOnEnemy" }),
		},
		["elemental_hit_area_of_effect_+100%_final_vs_enemy_with_associated_ailment"] = {
		},
		["elemental_hit_no_physical_chaos_damage"] = {
			flag("DealNoPhysical"),
			flag("DealNoChaos"),
			flag("DealNoFire", { type = "SkillPart", skillPartList = { 3, 4 } }),
			flag("DealNoFire", { type = "SkillPart", skillPartList = { 5, 6 } }),
			flag("DealNoCold", { type = "SkillPart", skillPartList = { 1, 2 } }),
			flag("DealNoCold", { type = "SkillPart", skillPartList = { 5, 6 } }),
			flag("DealNoLightning", { type = "SkillPart", skillPartList = { 1, 2 } }),
			flag("DealNoLightning", { type = "SkillPart", skillPartList = { 3, 4 } }),
		},
		["active_skill_base_area_of_effect_radius"] = {
			skill("radius", nil, { type = "SkillPart", skillPartList = { 2, 4, 6 } }),
		},
		["deal_no_non_elemental_damage"] = {
			-- Display only
		},
		["elemental_hit_no_damage_of_unchosen_elemental_type"] = {
			-- Display only
		},
		["quality_display_elemental_hit_is_gem"] = {
			-- Display only
		},
	},
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Ignited" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Chilled" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Frozen" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Shocked" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Scorched" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Brittle" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Sapped" })
#mods

#skill ElementalHitAltX
#flags attack projectile
	parts = {
		{
			name = "Attack",
			area = false,
		},
		{
			name = "AoE Explosion",
			area = true,
		},
	},
	statMap = {
		["elemental_hit_damage_+%_final_per_enemy_elemental_ailment"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "Multiplier", var = "ElementalHitAilmentOnEnemy" }),
		},
		["elemental_hit_no_physical_chaos_damage"] = {
			flag("DealNoPhysical"),
			flag("DealNoChaos"),
		},
		["active_skill_base_area_of_effect_radius"] = {
			skill("radius", nil, { type = "SkillPart", skillPart = 2 }),
		},
		["deal_no_non_elemental_damage"] = {
			-- Display only
		},
		["quality_display_elemental_hit_is_gem"] = {
			-- Display only
		},
	},
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Ignited" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Chilled" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Frozen" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Shocked" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Scorched" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Brittle" })
#baseMod mod("Multiplier:ElementalHitAilmentOnEnemy", "BASE", 1, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Sapped" })
#mods

#skill EnsnaringArrow
#flags attack projectile area
	statMap = {
		["tethered_enemies_take_attack_projectile_damage_taken_+%"] = {
			mod("ProjectileAttackDamageTaken", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Debuff", effectName = "Ensnared", effectStackVar = "EnsnareStackCount", effectStackLimit = 1 }),
		},
	},
#mods

#skill EtherealKnives
#flags spell projectile
#mods

#skill EtherealKnivesAltX
#flags spell projectile
#mods

#skill EtherealKnivesAltY
#flags spell projectile
#mods

#skill ExplosiveArrow
#flags attack projectile area duration
	parts = {
		{
			name = "Explosion (# of fuses)",
			area = true,
			stages = true,
		},
		{
			name = "Explosion (Maximum Sustainable Fuses)",
			area = true,
		},
		{
			name = "Arrow",
			area = false,
		},
	},
	explosiveArrowFunc = function(activeSkill, output, globalOutput, globalBreakdown, env)
		local t_insert = table.insert
		local s_format = string.format

		if activeSkill.skillPart ~= 1 and activeSkill.skillPart ~= 2 then
			-- This doesn't apply to the "Arrow" skill part. That works like a normal skill.
			return
		end

		local modDB = env.modDB
		local enemyDB = activeSkill.actor.enemy.modDB
		local skillModList = activeSkill.skillModList
		local duration = calcSkillDuration(skillModList, activeSkill.skillCfg, activeSkill.skillData, env, enemyDB)
		local fuseLimit = skillModList:Sum("BASE", activeSkill.skillCfg, "ExplosiveArrowMaxFuseCount")
		local activeTotems
		if activeSkill.skillFlags.totem then
			activeTotems = modDB:Override(nil, "TotemsSummoned") or skillModList:Sum("BASE", activeSkill.skillCfg, "ActiveTotemLimit", "ActiveBallistaLimit")
		end

		local barrageProjectiles = nil
		if skillModList:Flag(nil, "SequentialProjectiles") and not skillModList:Flag(nil, "OneShotProj") and not skillModList:Flag(nil,"NoAdditionalProjectiles") and not skillModList:Flag(nil, "TriggeredBySnipe") then
			barrageProjectiles = skillModList:Sum("BASE", activeSkill.skillCfg, "ProjectileCount")
			activeSkill.skillData.dpsMultiplier = activeSkill.skillData.dpsMultiplier / barrageProjectiles  -- cancel out the normal dps multiplier from barrage that applies to most other skills
		end

		local fuseApplicationRate = (output.HitChance / 100) * globalOutput.Speed * activeSkill.skillData.dpsMultiplier * (barrageProjectiles or 1)
		local initialApplicationRate = fuseApplicationRate
		if activeSkill.skillFlags.totem then
			fuseApplicationRate = fuseApplicationRate * activeTotems
		end

		-- Calculate the max number of fuses you can sustain
		-- Does not take into account mines or traps
		if activeSkill.skillPart == 2 then
			local maximum = math.min(math.floor(fuseApplicationRate * duration) + 1, fuseLimit)
			skillModList:NewMod("Multiplier:ExplosiveArrowStage", "BASE", maximum, "Base")
			skillModList:NewMod("Multiplier:ExplosiveArrowStageAfterFirst", "BASE", maximum - 1, "Base")
			globalOutput.MaxExplosiveArrowFuseCalculated = maximum
		else
			globalOutput.MaxExplosiveArrowFuseCalculated = nil
		end

		-- Calculate explosion rate
		local timeToMaxFuses = fuseLimit / fuseApplicationRate
		if activeSkill.skillPart == 2 or (activeSkill.skillPart == 1 and (activeSkill.activeStageCount or 0) + 1 >= fuseLimit) then
			globalOutput.HitTime = math.min(duration, timeToMaxFuses)
		else
			-- Number of fuses is less than the limit, so the entire fuse duration applies
			globalOutput.HitTime = duration
		end

		globalOutput.HitSpeed = 1 / globalOutput.HitTime

		if globalBreakdown and globalOutput.MaxExplosiveArrowFuseCalculated then
			globalBreakdown.MaxExplosiveArrowFuseCalculated = {}
			t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("%.2f ^8(attack speed)", globalOutput.Speed))
			if output.HitChance < 100 then
				t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("x %.2f ^8(hit chance)", output.HitChance / 100))
			end
			t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("x %.2f ^8(projectiles)", barrageProjectiles or 1))
			if activeSkill.skillFlags.totem then
				t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("= %.2f ^8(fuse rate)", initialApplicationRate))
				t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("x %d ^8(active totems)", activeTotems))
				t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("= %.2f ^8(fuse rate)", fuseApplicationRate))
			else
				t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("= %.2f ^8(fuse rate)", fuseApplicationRate))
			end
			t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("x %.2f ^8(duration)", duration))
			t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("+ 1 ^8(initial hit)"))
			t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("= %.2f", (fuseApplicationRate * duration) + 1))
			t_insert(globalBreakdown.MaxExplosiveArrowFuseCalculated, s_format("= %d ^8(rounded down, capped at max)", globalOutput.MaxExplosiveArrowFuseCalculated))

			globalBreakdown.ExplosionsPerSecond = {}
			t_insert(globalBreakdown.ExplosionsPerSecond, s_format("1 ^8(second)"))
			t_insert(globalBreakdown.ExplosionsPerSecond, s_format(" / %d ^8(max fuses)", globalOutput.MaxExplosiveArrowFuseCalculated))
			t_insert(globalBreakdown.ExplosionsPerSecond, s_format(" / %.2f ^8(fuse rate)", fuseApplicationRate))
			t_insert(globalBreakdown.ExplosionsPerSecond, s_format("= %.2f ^8(explosions/s)", globalOutput.HitSpeed))

		end
	end,
	statMap = {
		["explosive_arrow_explosion_minimum_added_fire_damage"] = {
			mod("FireMin", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 1, 2 } }),
		},
		["explosive_arrow_explosion_maximum_added_fire_damage"] = {
			mod("FireMax", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 1, 2 } }),
		},
		["fuse_arrow_explosion_radius_+_per_fuse_arrow_orb"] = {
			skill("radiusExtra", nil, { type = "Multiplier", var = "ExplosiveArrowStage", limitVar = "ExplosiveArrowMaxBonusRadius", limitTotal = true }),
		},
		["explosive_arrow_explosion_base_damage_+permyriad"] = {
			skill("baseMultiplier", nil, { type = "SkillPart", skillPartList = { 1, 2 } }),
			div = -10000,
		},
		["explosive_arrow_hit_damage_+%_final_per_stack"] = {
			mod("Damage", "MORE", nil, 0, KeywordFlag.Hit, { type = "SkillPart", skillPartList = { 1, 2 } }, { type = "Multiplier", var = "ExplosiveArrowStage" }),
		},
		["explosive_arrow_ailment_damage_+%_final_per_stack"] = {
			mod("Damage", "MORE", nil, 0, KeywordFlag.Ailment, { type = "SkillPart", skillPartList = { 1, 2 } }, { type = "Multiplier", var = "ExplosiveArrowStage" }),
		},
		["explosive_arrow_maximum_bonus_explosion_radius"] = {
			mod("Multiplier:ExplosiveArrowMaxBonusRadius", "BASE", nil),
		},
		["explosive_arrow_stack_limit"] = {
			mod("Multiplier:ExplosiveArrowMaxStages", "BASE", nil, 0, 0, { type = "SkillPart", skillPart = 1 }),
			mod("ExplosiveArrowMaxFuseCount", "BASE", nil),
		},
		["quality_display_explosive_arrow_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("radius", 15)
#baseMod skill("showAverage", true, { type = "SkillPart", skillPartList = { 1, 2 } })
#baseMod mod("Damage", "MORE", 100, 0, 0, { type = "SkillPart", skillPartList = { 1, 2 } }, { type = "Multiplier", var = "ExplosiveArrowStageAfterFirst" })
#mods

#skill ExplosiveConcoction
#flags attack area projectile
	parts = {
		{
			name = "No Flasks",
		},
		{
			name = "Sapphire",
		},
		{
			name = "Topaz",
		},
		{
			name = "Ruby",
		},
		{
			name = "Sapphire + Topaz",
		},
		{
			name = "Sapphire + Ruby",
		},
		{
			name = "Topaz + Ruby",
		},
		{
			name = "All Flasks",
		},
	},
	statMap = {
		["flask_throw_minimum_cold_damage_if_used_sapphire_flask"] = {
			mod("ColdMin", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 2, 5, 6, 8 } }),
		},
		["flask_throw_maximum_cold_damage_if_used_sapphire_flask"] = {
			mod("ColdMax", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 2, 5, 6, 8 } }),
		},
		["flask_throw_minimum_lightning_damage_if_used_topaz_flask"] = {
			mod("LightningMin", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 3, 5, 7, 8 } }),
		},
		["flask_throw_maximum_lightning_damage_if_used_topaz_flask"] = {
			mod("LightningMax", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 3, 5, 7, 8 } }),
		},
		["flask_throw_ruby_flask_ignite_dot_multiplier_+"] = {
			mod("FireDotMultiplier", "BASE", nil, 0, KeywordFlag.Ignite, { type = "SkillPart", skillPartList = { 4, 6, 7, 8 } }),
		},
	},
#mods

#skill ExplosiveConcoctionAltX
#flags attack area projectile
	parts = {
		{
			name = "No Flasks",
		},
		{
			name = "Sapphire",
		},
		{
			name = "Topaz",
		},
		{
			name = "Ruby",
		},
		{
			name = "Sapphire + Topaz",
		},
		{
			name = "Sapphire + Ruby",
		},
		{
			name = "Topaz + Ruby",
		},
		{
			name = "All Flasks",
		},
	},
	statMap = {
		["flask_throw_minimum_cold_damage_if_used_sapphire_flask"] = {
			mod("ColdMin", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 2, 5, 6, 8 } }),
		},
		["flask_throw_maximum_cold_damage_if_used_sapphire_flask"] = {
			mod("ColdMax", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 2, 5, 6, 8 } }),
		},
		["flask_throw_minimum_lightning_damage_if_used_topaz_flask"] = {
			mod("LightningMin", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 3, 5, 7, 8 } }),
		},
		["flask_throw_maximum_lightning_damage_if_used_topaz_flask"] = {
			mod("LightningMax", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 3, 5, 7, 8 } }),
		},
		["flask_throw_ruby_flask_critical_strike_multiplier_+"] = {
			mod("CritMultiplier", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 4, 6, 7, 8 } }),
		},
	},
#mods

#skill ExplosiveTrap
#flags spell trap area
	parts = {
		{
			name = "One explosion hitting",
		},
		{
			name = "Average explosions hitting",
		},
		{
			name = "All explosions hitting",
		},
	},
	preDamageFunc = function(activeSkill, output, breakdown)
		local skillCfg = activeSkill.skillCfg
		local skillData = activeSkill.skillData
		local skillPart = activeSkill.skillPart
		local skillModList = activeSkill.skillModList
		local t_insert = table.insert
		local s_format = string.format

		local function hitChance(enemyRadius, areaDamageRadius, areaSpreadRadius) -- not to be confused with attack hit chance
			local damagingAreaRadius = areaDamageRadius + enemyRadius - 1	-- radius where area damage can land to hit the enemy;
			-- -1 because of two assumptions: PoE coordinates are integers and damage is not registered if the two areas only share a point or vertex. If either is not correct, then -1 is not needed.
			return math.min(damagingAreaRadius * damagingAreaRadius / (areaSpreadRadius * areaSpreadRadius), 1)
		end
		local enemyRadius = skillModList:Override(skillCfg, "EnemyRadius") or skillModList:Sum("BASE", skillCfg, "EnemyRadius")
		local fullRadius = output.AreaOfEffectRadiusSecondary
		local overlapChance = 0
		local marginWidth = skillData.radiusTertiaryBaseMargin * 2 + 1
		for smallRadius, occurrenceCount in pairs(output.AreaOfEffectRadiusTertiaryOccurrences) do
			overlapChance = overlapChance + hitChance(enemyRadius, smallRadius, fullRadius) * occurrenceCount / marginWidth
		end
		output.OverlapChance = overlapChance * 100
		local smallExplosionsPerTrap = skillModList:Sum("BASE", skillCfg, "SmallExplosions")
		output.SmallExplosionsPerTrap = smallExplosionsPerTrap
		if breakdown then
			breakdown.OverlapChance = { }
			t_insert(breakdown.OverlapChance, "Chance for individual small explosion to land within range to damage enemy:")
			t_insert(breakdown.OverlapChance, "^8= (area where a small explosion can spawn to damage enemy) / (total area)")
			t_insert(breakdown.OverlapChance, "^8= (^7tertiary radius^8 + ^7enemy radius^8 - 1) ^ 2 / ^7secondary radius^8 ^ 2")
			t_insert(breakdown.OverlapChance, "^8Result is the weighted sum of overlap chances for each possible tertiary radius")
			local radii = {}
			local numRadii = 0
			for radius in pairs(output.AreaOfEffectRadiusTertiaryOccurrences) do
				t_insert(radii, radius)
				numRadii = numRadii + 1
			end
			table.sort(radii)
			for i, smallRadius in ipairs(radii) do
				t_insert(breakdown.OverlapChance, s_format("^8(^7%d^8 +^7 %d^8 - 1) ^ 2 /^7 %d^8 ^ 2 *^7 %d/%d%s",
					smallRadius, enemyRadius, fullRadius, output.AreaOfEffectRadiusTertiaryOccurrences[smallRadius],
					marginWidth, i == numRadii and "" or " ^8+"))
			end
			t_insert(breakdown.OverlapChance, s_format("^8=^7 %.3f^8%%", output.OverlapChance))
		end
		local dpsMultiplier = 1
		if skillPart == 2 then
			dpsMultiplier = 1 + smallExplosionsPerTrap * overlapChance
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, "^8= 1 + ^7small explosions^8 * ^7overlap chance^8")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8= 1 +^7 %d^8 *^7 %.2f^8", smallExplosionsPerTrap, overlapChance))
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMultiplier))
			end
		elseif skillPart == 3 then
			dpsMultiplier = 1 + smallExplosionsPerTrap
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8= 1 +^7 %d (small explosions)", dpsMultiplier))
			end
		end
		if dpsMultiplier ~= 1 then
			skillData.dpsMultiplier = (skillData.dpsMultiplier or 1) * dpsMultiplier
			output.SkillDPSMultiplier = (output.SkillDPSMultiplier or 1) * dpsMultiplier
		end
	end,
	statMap = {
		["shrapnel_trap_number_of_secondary_explosions"] = {
			mod("SmallExplosions", "BASE", nil),
		},
		["quality_display_explosive_trap_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("radiusLabel", "Primary Explosion:")
#baseMod skill("radiusSecondaryLabel", "Secondary Area:")
#baseMod skill("radiusTertiaryLabel", "Secondary Explosion:")
#baseMod skill("radiusTertiaryBaseMargin", 30)
#mods

#skill ExplosiveTrapAltX
#flags spell trap area
	parts = skills.ExplosiveTrap.parts,
	preDamageFunc = skills.ExplosiveTrap.preDamageFunc,
	statMap = skills.ExplosiveTrap.statMap,
	baseMods = skills.ExplosiveTrap.baseMods,
#mods

#skill ExplosiveTrapAltY
#flags spell trap area
#mods

#skill FireTrap
#flags spell trap area duration
#baseMod skill("dotIsArea", true)
#baseMod flag("dotIsBurningGround")
#baseMod skill("radius", 15)
#mods

#skill FireTrapAltX
#flags spell trap area duration
#baseMod skill("radius", 15)
#mods

#skill FlamethrowerTrap
#flags spell trap area duration
	parts = {
		{
			name = "One trap (good placement)",
		},
		{
			name = "One trap (bad placement)",
		},
		{
			name = "Average # traps (good placement)",
		},
		{
			name = "Average # traps (bad placement)",
		},
	},
	preDamageFunc = function(activeSkill, output, breakdown)
		-- Unknown stats provided by asking GGG
		local t_insert = table.insert
		local s_format = string.format

		local duration = output.Duration
		local cooldown = output.TrapCooldown
		local averageActiveTraps = duration / cooldown
		output.AverageActiveTraps = averageActiveTraps
		if activeSkill.skillPart == 2 or activeSkill.skillPart == 4 then
			activeSkill.skillData.hitTimeOverride = 0.3
		else
			activeSkill.skillData.hitTimeOverride = 0.1
		end

		if activeSkill.skillPart == 3 or activeSkill.skillPart == 4 then
			activeSkill.skillData.dpsMultiplier = (activeSkill.skillData.dpsMultiplier or 1) * averageActiveTraps
		end

		if breakdown then
			breakdown.AverageActiveTraps = { }
			t_insert(breakdown.AverageActiveTraps, "Average active traps, not considering stored cooldown uses:")
			t_insert(breakdown.AverageActiveTraps, s_format("%.2f^8 (skill duration)", duration))
			t_insert(breakdown.AverageActiveTraps, s_format("/ %.2f^8 (cooldown)", cooldown))
			t_insert(breakdown.AverageActiveTraps, s_format("= %.2f traps", averageActiveTraps))
		end
	end,
	statMap = {
		["flamethrower_trap_damage_+%_final_vs_burning_enemies"] = {
			mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "ActorCondition", actor = "enemy", var = "Burning" }),
		},
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
	},
#baseMod skill("radius", 32)
#mods

#skill FlickerStrike
#flags attack melee duration
	statMap = {
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["flicker_strike_buff_movement_speed_+%"] = {
			mod("MovementSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
	},
#mods

#skill FlickerStrikeAltX
#flags attack melee duration
	statMap = {
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["flicker_strike_buff_movement_speed_+%"] = {
			mod("MovementSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
	},
#mods

#skill VaalFlickerStrike
#flags attack melee duration
	statMap = {
		["active_skill_ailment_damage_+%_final"] = {
			mod("Damage", "MORE", nil, bit.bor(ModFlag.MeleeHit, ModFlag.Ailment)),
		},
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["base_melee_attack_repeat_count"] = {
			mod("RepeatCount", "BASE", nil)
		},
	},
#baseMod flag("OnlyFinalRepeat")
#baseMod flag("FinalRepeatSumsDamage")
#mods

#skill Frenzy
#flags attack melee projectile
	statMap = {
		["frenzy_skill_attack_damage_+%_final_per_frenzy_charge"] = {
			mod("Damage", "MORE", nil, ModFlag.Attack, 0, { type = "Multiplier", var = "FrenzyCharge" }),
		},
		["frenzy_skill_attack_speed_+%_final_per_frenzy_charge"] = {
			mod("Speed", "MORE", nil, ModFlag.Attack, 0, { type = "Multiplier", var = "FrenzyCharge" }),
		},
		["quality_display_frenzy_is_gem"] = {
			-- Display only
		},
		["quality_display_active_skill_attack_speed_per_frenzy_is_gem"] = {
			-- Display only
		},
	},
#mods

#skill FrenzyAltX
#flags attack melee projectile
	statMap = {
		["frenzy_skill_attack_damage_+%_final_per_frenzy_charge"] = {
			mod("Damage", "MORE", nil, ModFlag.Attack, 0, { type = "Multiplier", var = "FrenzyCharge" }),
		},
		["frenzy_skill_attack_speed_+%_final_per_frenzy_charge"] = {
			mod("Speed", "MORE", nil, ModFlag.Attack, 0, { type = "Multiplier", var = "FrenzyCharge" }),
		},
		["quality_display_frenzy_is_gem"] = {
			-- Display only
		},
		["quality_display_active_skill_attack_speed_per_frenzy_is_gem"] = {
			-- Display only
		},
	},
#mods

#skill FrostBlades
#flags attack melee projectile
	parts = {
		{
			name = "Melee hit",
			melee = true,
			projectile = false,
		},
		{
			name = "Icy blades",
			melee = false,
			projectile = true,
		},
	},
	statMap = {
		["active_skill_hit_ailment_damage_with_projectile_+%_final"] = {
			mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPart = 2 })
		},
	},
#mods

#skill FrostBladesAltX
#flags attack melee projectile area dotFromAttack
	parts = {
		{
			name = "Melee Hit",
			attack = true,
			melee = true,
			projectile = true,
			area = false,
		},
		{
			name = "Ground DoT",
			attack = false,
			hit = false,
			melee = false,
			projectile = false,
			area = true,
		},
	},
	statMap = {
		["base_cold_damage_to_deal_per_minute"] = {
			skill("ColdDot", nil, { type = "SkillPart", skillPart = 2 }),
			div = 60,
		},
	},
#baseMod skill("dotIsArea", true, { type = "SkillPart", skillPart = 2 })
#mods

#skill GalvanicArrow
#flags attack projectile area
	parts = {
		{
			name = "Arrow",
			area = false,
		},
		{
			name = "Cone",
			area = true,
		},
	},
#baseMod skill("radius", 28)
#mods

#skill GalvanicArrowAltX
#flags attack area
#baseMod skill("radius", 28)
#mods

#skill GalvanicArrowAltY
#flags attack projectile area
	parts = {
		{
			name = "Arrow",
			area = false,
		},
		{
			name = "Cone",
			area = true,
		},
	},
#baseMod skill("radius", 28)
#mods

#skill GlacialShieldSwipe
#flags attack melee area shieldAttack
#mods

#skill Grace
#flags spell aura area
	statMap = {
		["grace_aura_evasion_rating_+%_final"] = {
			mod("Evasion", "MORE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
		["base_evasion_rating"] = {
			mod("Evasion", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
	},
#baseMod skill("radius", 40)
#mods

#skill VaalGrace
#flags spell aura area duration vaal
	statMap = {
		["chance_to_evade_attacks_%"] = {
			mod("EvadeChance", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
	},
#baseMod skill("radius", 40)
#mods

#skill Haste
#flags spell aura area
	statMap = {
		["cast_speed_+%_granted_from_skill"] = {
			mod("Speed", "INC", nil, ModFlag.Cast, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
		["attack_speed_+%_granted_from_skill"] = {
			mod("Speed", "INC", nil, ModFlag.Attack, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
		["base_movement_velocity_+%"] = {
			mod("MovementSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
	},
#baseMod skill("radius", 40)
#mods

#skill VaalHaste
#flags spell aura area duration vaal
	statMap = {
		["cast_speed_+%_granted_from_skill"] = {
			mod("Speed", "INC", nil, ModFlag.Cast, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
		["attack_speed_+%_granted_from_skill"] = {
			mod("Speed", "INC", nil, ModFlag.Attack, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
		["base_movement_velocity_+%"] = {
			mod("MovementSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
	},
#baseMod skill("radius", 40)
#mods

#skill Hatred
#flags spell aura area
	statMap = {
		["physical_damage_%_to_add_as_cold"] = {
			mod("PhysicalDamageGainAsCold", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
	},
#baseMod skill("radius", 40)
#mods

#skill HeraldOfAgony
#flags cast minion permanentMinion
	minionList = {
		"HeraldOfAgonySpiderPlated",
	},
	statMap = {
		["skill_buff_grants_chance_to_poison_%"] = {
			mod("PoisonChance", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["herald_of_agony_poison_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, KeywordFlag.Poison, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["scorpion_minion_physical_damage_+%"] = {
			mod("MinionModifier", "LIST", { type = "HeraldOfAgonySpiderPlated", mod = mod("PhysicalDamage", "INC", nil, 0, 0, { type = "Multiplier", actor = "parent", var = "VirulenceStack", limitVar = "VirulenceStacksMax", limitActor = "parent"  })})
		},
		["scorpion_minion_attack_speed_+%"] = {
			mod("MinionModifier", "LIST", { type = "HeraldOfAgonySpiderPlated", mod = mod("Speed", "INC", nil, 0, 0, { type = "Multiplier", actor = "parent", var = "VirulenceStack", limitVar = "VirulenceStacksMax", limitActor = "parent" })})
		},
		["scorpion_minion_minimum_added_physical_damage"] = {
			mod("MinionModifier", "LIST", { type = "HeraldOfAgonySpiderPlated", mod = mod("PhysicalMin", "BASE", nil, 0, 0, { type = "Multiplier", actor = "parent", var = "VirulenceStack", limitVar = "VirulenceStacksMax", limitActor = "parent" })})
		},
		["scorpion_minion_maximum_added_physical_damage"] = {
			mod("MinionModifier", "LIST", { type = "HeraldOfAgonySpiderPlated", mod = mod("PhysicalMax", "BASE", nil, 0, 0, { type = "Multiplier", actor = "parent", var = "VirulenceStack", limitVar = "VirulenceStacksMax", limitActor = "parent" })})
		},
		["maximum_virulence_stacks"] = {
			mod("Multiplier:VirulenceStacksMax", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura", effectName = "Virulence Stack Limit", unscalable = true }),
		},
		["quality_display_herald_of_agony_is_gem"] = {
			-- Display only
		},
	},
#mods

#skill HeraldOfIce
#flags cast area
	statMap = {
		["spell_minimum_added_cold_damage"] = {
			mod("ColdMin", "BASE", nil, 0, KeywordFlag.Spell, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["spell_maximum_added_cold_damage"] = {
			mod("ColdMax", "BASE", nil, 0, KeywordFlag.Spell, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["attack_minimum_added_cold_damage"] = {
			mod("ColdMin", "BASE", nil, 0, KeywordFlag.Attack, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["attack_maximum_added_cold_damage"] = {
			mod("ColdMax", "BASE", nil, 0, KeywordFlag.Attack, { type = "GlobalEffect", effectType = "Buff" }),
		},
	},
#mods

#skill IceShot
#flags attack projectile area duration
	parts = {
		{
			name = "Arrow",
			area = false,
		},
		{
			name = "Cone",
			area = true,
		},
	},
#baseMod mod("SkillPhysicalDamageConvertToCold", "BASE", 40, 0, 0, { type = "SkillPart", skillPart = 2 })
#mods

#skill IceShotAltX
#flags attack projectile area duration
	parts = {
		{
			name = "Arrow",
			area = false,
		},
		{
			name = "Cone",
			area = true,
		},
	},
#baseMod mod("SkillPhysicalDamageConvertToCold", "BASE", 40, 0, 0, { type = "SkillPart", skillPart = 2 })
#mods

#skill VaalIceShot
#flags attack projectile area duration
#mods

#skill IceTrap
#flags spell trap area
#baseMod skill("radiusLabel", "First Explosion:")
#baseMod skill("radiusSecondaryLabel", "Second Explosion:")
#baseMod skill("radiusTertiaryLabel", "Third Explosion:")
#mods

#skill IceTrapAltX
#flags spell trap area
#baseMod skill("radiusLabel", "First Explosion:")
#baseMod skill("radiusSecondaryLabel", "Second Explosion:")
#mods

#skill Lacerate
#flags attack melee area
	parts = {
		{
			name = "One slash",
		},
		{
			name = "Both slashes",
		},
	},
	statMap = {
		["attack_speed_+%_if_changed_stance_recently"] = {
			mod("Speed", "INC", nil, ModFlag.Attack, 0, { type = "Condition", var = "ChangedStanceRecently" }),
		},
	},
#baseMod skill("radius", 38)
#baseMod skill("dpsMultiplier", 2, { type = "SkillPart", skillPart = 2 })
#mods

#skill LacerateAltX
#flags attack melee area
	parts = {
		{
			name = "One slash",
		},
		{
			name = "Both slashes",
		},
	},
#baseMod skill("radius", 38)
#baseMod skill("dpsMultiplier", 2, { type = "SkillPart", skillPart = 2 })
#mods

#skill LacerateAltY
#flags attack melee area
	parts = {
		{
			name = "One slash",
		},
		{
			name = "Both slashes",
		},
	},
#baseMod skill("radius", 38)
#baseMod skill("dpsMultiplier", 2, { type = "SkillPart", skillPart = 2 })
#mods

#skill LancingSteel
#flags attack projectile
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			local percentReducedProjectiles = (output.ProjectileCount - 1) / output.ProjectileCount
			local mult = (activeSkill.skillModList:More(activeSkill.skillCfg, "LancingSteelSubsequentDamage") - 1) * 100 * percentReducedProjectiles
			activeSkill.skillData.dpsMultiplier = output.ProjectileCount
			activeSkill.skillModList:NewMod("Damage", "MORE", mult, "Skill:LancingSteel")
		end
	end,
	parts = {
		{
			name = "Single Projectile Hit",
		},
		{
			name = "All Projectiles Hit",
		},
	},
	statMap = {
		["number_of_projectiles_to_fire_+%_final_per_steel_ammo_consumed"] = {
			mod("ProjectileCount", "MORE", nil, 0, 0, { type = "Multiplier", var = "SteelShardConsumed", limit = 4 } )
		},
		["lancing_steel_damage_+%_at_close_range"] = {
			mod("Damage", "INC", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "DistanceRamp", ramp = {{10,1},{70,0}} }),
		},
		["lancing_steel_damage_+%_final_after_first_hit_on_target"] = {
			mod("LancingSteelSubsequentDamage", "MORE", nil, 0, 0, { type = "SkillPart", skillPart = 2 } ),
		},
	},
#mods

#skill LancingSteelAltX
#flags attack projectile
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			local percentReducedProjectiles = (output.ProjectileCount - 1) / output.ProjectileCount
			local mult = (activeSkill.skillModList:More(activeSkill.skillCfg, "LancingSteelSubsequentDamage") - 1) * 100 * percentReducedProjectiles
			activeSkill.skillData.dpsMultiplier = output.ProjectileCount
			activeSkill.skillModList:NewMod("Damage", "MORE", mult, "Skill:LancingSteelAltX")
		end
	end,
	parts = {
		{
			name = "Single Projectile Hit",
		},
		{
			name = "All Projectiles Hit",
		},
	},
	statMap = {
		["lancing_steel_damage_+%_final_after_first_hit_on_target"] = {
			mod("LancingSteelSubsequentDamage", "MORE", nil, 0, 0, { type = "SkillPart", skillPart = 2 } ),
		},
	},
#mods

#skill LightningArrow
#flags attack projectile
#baseMod skill("radius", 18)
#mods

#skill LightningArrowAltX
#flags attack projectile
	statMap = {
		["lightning_arrow_stack_limit"] = {
			mod("Multiplier:LightningArrowofElectrocutionMaxStages", "BASE", nil)
		},
		["lightning_arrow_alt_strike_frequency_ms"] = {
			skill("hitFrequency", nil),
			div = 1000,
		},
	},
#baseMod skill("dpsMultiplier", 1, { type = "Multiplier", var = "LightningArrowofElectrocutionStage" })
#mods

#skill VaalLightningArrow
#flags attack projectile
	parts = {
		{
			name = "1 Projectile",
		},
		{
			name = "All Projectiles",
		},
	},
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.dpsMultiplier = output.ProjectileCount
		end
	end,
	statMap = {
		["projectiles_barrage"] = {
		},
		["base_skill_show_average_damage_instead_of_dps"] = {
		},
		["quality_display_base_additional_arrows_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("radius", 18)
#mods

#skill LightningStrike
#flags attack melee projectile
	parts = {
		{
			name = "Melee hit",
			melee = true,
			projectile = false,
		},
		{
			name = "Projectiles",
			melee = false,
			projectile = true,
		},
	},
	statMap = {
		["active_skill_hit_ailment_damage_with_projectile_+%_final"] = {
			mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPart = 2 })
		},
	},
#mods

#skill LightningStrikeAltX
#flags attack melee projectile
	parts = {
		{
			name = "Melee hit",
			melee = true,
			projectile = false,
		},
		{
			name = "Projectiles",
			melee = false,
			projectile = true,
		},
	},
	statMap = {
		["skill_damage_+%_final_per_chain_from_skill_specific_stat"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "PerStat", stat = "Chain" }),
		},
		["active_skill_hit_ailment_damage_with_projectile_+%_final"] = {
			mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPart = 2 })
		},
	},
#mods

#skill VaalLightningStrike
#flags attack melee duration vaal
	parts = {
		{
			name = "Melee hit",
			melee = true,
			projectile = false,
		},
		{
			name = "Projectiles",
			melee = false,
			projectile = true,
		},
	},
	statMap = {
		["vaal_lightning_strike_beam_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
		},
	},
#mods

#skill MirrorArrow
#flags attack projectile minion duration
	minionList = {
		"ArrowClone",
	},
#baseMod skill("minionUseBowAndQuiver", true)
#mods

#skill MirrorArrowAltX
#flags attack projectile minion duration
	minionList = {
		"ArrowCloneRoA",
	},
#baseMod skill("minionUseBowAndQuiver", true)
#mods

#skill MirrorArrowAltY
#flags attack projectile minion duration
	minionList = {
		"ArrowCloneEle",
	},
#baseMod skill("minionUseBowAndQuiver", true)
#mods

#skill PestilentStrike
#flags attack melee area duration
#baseMod skill("radius", 27)
#mods

#skill PhaseRun
#flags spell duration
	statMap = {
		["phase_run_melee_physical_damage_+%_final"] = {
			mod("PhysicalDamage", "MORE", nil, ModFlag.Melee, 0, { type = "SkillType", skillType = SkillType.Totem, neg = true }, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["base_movement_velocity_+%"] = {
			mod("MovementSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
	},
#mods

#skill PlagueBearer
#flags spell area
	statMap = {
		["corrosive_shroud_poison_damage_+%_final_while_accumulating_poison"] = {
			mod("Damage", "MORE", nil, 0, KeywordFlag.Poison, { type = "GlobalEffect", effectType = "Buff", modCond = "PlagueBearerIncubating" }),
		},
	},
#baseMod skill("radius", 25)
#mods

#skill PoachersMark
#flags spell curse duration mark
	statMap = {
		["life_granted_when_hit_by_attacks"] = {
			mod("SelfLifeOnHit", "BASE", nil, ModFlag.Attack, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
		["mana_granted_when_hit_by_attacks"] = {
			mod("SelfManaOnHit", "BASE", nil, ModFlag.Attack, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
		["base_additional_physical_damage_reduction_%"] = {
			mod("PhysicalDamageReduction", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
		["minimum_added_physical_damage_taken"] = {
			mod("SelfPhysicalMin", "BASE", nil, ModFlag.Hit, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
		["maximum_added_physical_damage_taken"] = {
			mod("SelfPhysicalMax", "BASE", nil, ModFlag.Hit, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
	},
#baseMod skill("debuff", true)
#mods

#skill Precision
#flags spell aura area
	statMap = {
		["accuracy_rating"] = {
			mod("Accuracy", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
		["skill_buff_grants_critical_strike_chance_+%"] = {
			mod("CritChance", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
	},
#baseMod skill("radius", 40)
#mods

#skill SnipersMark
#flags spell curse duration mark
	statMap = {
		["projectile_damage_taken_+%"] = {
			mod("ProjectileDamageTaken", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
		["projectiles_hitting_self_split_into_x"] = {
			mod("SelfSplitCount", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
	},
#baseMod skill("debuff", true)
#mods

#skill StormRain
#flags attack area projectile
	parts = {
		{
			name = "Arrow",
		},
		{
			name = "Beam",
		},
	},
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.hitTimeOverride = activeSkill.skillData.hitFrequency / (1 + activeSkill.skillModList:Sum("INC", activeSkill.skillCfg, "StormRainBeamFrequency") / 100)
			activeSkill.skillData.dpsMultiplier = activeSkill.skillData.beamOverlapMultiplier or 1
		end
	end,
	statMap = {
		["prismatic_rain_beam_base_frequency_ms"] = {
			skill("hitFrequency", nil),
			div = 1000,
		},
		["prismatic_rain_beam_frequency_+%"] = {
			mod("StormRainBeamFrequency", "INC", nil),
		},
		["number_of_allowed_storm_arrows"] = {
			-- Display only
		},
		["quality_display_storm_rain_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("radius", 10, { type = "SkillPart", skillPart = 1 })
#baseMod skill("radiusLabel", "Arrow Explosion:", { type = "SkillPart", skillPart = 1 })
#baseMod skill("radiusSecondary", 12, { type = "SkillPart", skillPart = 2 })
#baseMod skill("radiusSecondaryLabel", "Beam Width:", { type = "SkillPart", skillPart = 2 })
#mods

#skill StormRainAltX
#flags attack area projectile
	 preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.hitTimeOverride = activeSkill.skillData.hitFrequency / (1 + activeSkill.skillModList:Sum("INC", activeSkill.skillCfg, "StormRainBeamFrequency") / 100)
			activeSkill.skillData.dpsMultiplier = math.min(activeSkill.skillData.activeArrowMultiplier or 1, activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "StormRainAllowedStormArrows"))
		end
	end,
	parts = {
		{
			name = "Arrow",
		},
		{
			name = "Beam",
		},
	},
	statMap = {
			["prismatic_rain_beam_base_frequency_ms"] = {
				skill("hitFrequency", nil),
				div = 1000,
			},
			["prismatic_rain_beam_frequency_+%"] = {
				mod("StormRainBeamFrequency", "INC", nil),
			},
			["number_of_allowed_storm_arrows"] = {
				mod("StormRainAllowedStormArrows", "BASE", nil)
			},
			["quality_display_storm_rain_is_gem"] = {
				-- Display only
			},
		},
#mods

#skill StormRainAltY
#flags attack area projectile
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 then
			activeSkill.skillData.hitTimeOverride = activeSkill.skillData.hitFrequency / (1 + activeSkill.skillModList:Sum("INC", activeSkill.skillCfg, "StormRainBeamFrequency") / 100)
			-- Max of 2 arrows, and each fires at each other, so 2 beams per tick
			activeSkill.skillData.dpsMultiplier = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "StormRainAllowedStormArrows")
		end
	end,
	parts = {
		{
			name = "Arrow",
		},
		{
			name = "Beam",
		},
	},
	statMap = {
		["prismatic_rain_beam_base_frequency_ms"] = {
			skill("hitFrequency", nil),
			div = 1000,
		},
		["prismatic_rain_beam_frequency_+%"] = {
			mod("StormRainBeamFrequency", "INC", nil),
		},
		["number_of_allowed_storm_arrows"] = {
			mod("StormRainAllowedStormArrows", "BASE", nil)
		},
		["quality_display_storm_rain_is_gem"] = {
			-- Display only
		},
	},
#mods

#skill Puncture
#flags attack melee projectile duration
	statMap = {
		["quality_display_active_skill_bleed_damage_final_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("bleedIsSkillEffect", true)
#mods

#skill PunctureAltX
#flags attack melee duration
	statMap = {
		["quality_display_active_skill_bleed_damage_final_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("bleedIsSkillEffect", true)
#mods

#skill PurityOfIce
#flags spell aura area
	statMap = {
		["base_cold_damage_resistance_%"] = {
			mod("ColdResist", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
		["base_maximum_cold_damage_resistance_%"] = {
			mod("ColdResistMax", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
	},
#baseMod skill("radius", 40)
#mods

#skill VaalImpurityOfIce
#flags spell aura area duration
	statMap = {
		["hits_ignore_my_cold_resistance"] = {
			flag("SelfIgnoreColdResistance", { type = "GlobalEffect", effectType = "AuraDebuff" }),
		},
		["base_maximum_cold_damage_resistance_%"] = {
			mod("ColdResistMax", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura" }),
		},
		["base_immune_to_freeze"] = {
			flag("FreezeImmune", { type = "GlobalEffect", effectType = "Aura"}),
		},
		["base_immune_to_chill"] = {
			flag("ChillImmune", { type = "GlobalEffect", effectType = "Aura"}),
		},
	},
#mods

#skill RainOfArrows
#flags attack projectile area
#baseMod skill("radius", 10)
#baseMod flag("OneShotProj")
#mods

#skill RainOfArrowsAltX
#flags attack projectile area
#baseMod flag("OneShotProj")
#mods

#skill RainOfArrowsAltY
#flags attack projectile area
#baseMod flag("OneShotProj")
#mods

#skill VaalRainOfArrows
#flags attack projectile area duration vaal
#baseMod skill("radius", 10)
#baseMod flag("OneShotProj")
#mods

#skill Reave
#flags attack melee area
	statMap = {
		["reave_area_of_effect_+%_final_per_stage"] = {
			mod("AreaOfEffect", "MORE", nil, 0, 0, { type = "Multiplier", var = "ReaveStage" }),
		},
		["reave_additional_max_stacks"] = {
			mod("Multiplier:ReaveMaxStages", "BASE", nil),
		}
	},
#baseMod skill("radius", 20)
#baseMod mod("Multiplier:ReaveMaxStages", "BASE", 8)
#mods

#skill ReaveAltX
#flags attack melee area
	statMap = {
		["reave_area_of_effect_+%_final_per_stage"] = {
			mod("AreaOfEffect", "MORE", nil, 0, 0, { type = "Multiplier", var = "ReaveofRefractionStage" }),
		},
		["reave_additional_max_stacks"] = {
			mod("Multiplier:ReaveofRefractionMaxStages", "BASE", nil),
		}
	},
#baseMod skill("radius", 20)
#baseMod mod("Multiplier:ReaveofRefractionMaxStages", "BASE", 8)
#mods

#skill VaalReave
#flags attack melee area vaal
	statMap = {
		["reave_area_of_effect_+%_final_per_stage"] = {
			mod("AreaOfEffect", "MORE", nil, 0, 0, { type = "Multiplier", var = "ReaveStage" }),
		},
		["reave_additional_max_stacks"] = {
			mod("Multiplier:ReaveMaxStages", "BASE", nil),
		},
	},
#baseMod skill("radius", 12)
#baseMod mod("Multiplier:ReaveMaxStages", "BASE", 4)
#mods

#skill ScourgeArrow
#flags attack projectile
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.hitTimeMultiplier = math.max(activeSkill.skillModList:Sum("BASE", cfg, "Multiplier:ScourgeArrowStage") - 0.5, 0.5) --First stage takes 0.5x time to channel compared to subsequent stages
	end,
	parts = {
		{
			name = "Release",
			stages = true,
		},
		{
			name = "Thorn Arrows",
			stages = true,
		},
	},
	statMap = {
		["virulent_arrow_damage_+%_final_per_stage"] = {
			mod("Damage", "MORE", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "Multiplier", var = "ScourgeArrowStage" }),
		},
		["virulent_arrow_pod_projectile_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type= "SkillPart", skillPart = 2 }),
		},
		["virulent_arrow_maximum_number_of_stacks"] = {
			mod("Multiplier:ScourgeArrowMaxStages", "BASE", nil),
		},
		["base_arrows_always_pierce"] = {
			flag("PierceAllTargets"),
		},
	},
#mods

#skill ScourgeArrowAltX
#flags attack projectile
	parts = {
		{
			name = "Release",
		},
		{
			name = "Thorn Arrows",
		},
	},
	statMap = {
		["virulent_arrow_damage_+%_final_per_stage"] = {
			mod("Damage", "MORE", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "Multiplier", var = "ScourgeArrowStage" }),
		},
		["virulent_arrow_pod_projectile_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type= "SkillPart", skillPart = 2 }),
		},
		["base_arrows_always_pierce"] = {
			flag("PierceAllTargets"),
		},
	},
#mods

#skill ShatteringSteel
#flags attack projectile area
	parts = {
		{
			name = "Projectile",
			area = false,
		},
		{
			name = "Cone AoE",
		},
	},
#baseMod skill("radius", 28)
#mods

#skill ShatteringSteelAltX
#flags attack projectile area
	parts = {
		{
			name = "Projectile",
			area = false,
		},
		{
			name = "Cone AoE",
		},
	},
	statMap = {
		["steel_ammo_consumed_per_use"] = {
			mod("Multiplier:MaxSteelShardsConsumed", "BASE", nil),
		},
		["shattering_steel_hit_damage_+%_final_scaled_by_projectile_distance_per_ammo_consumed"] = {
			mod("Damage", "MORE", nil, ModFlag.Hit, 0, { type = "Multiplier", var = "SteelShardConsumed", limitVar = "MaxSteelShardsConsumed" }, { type = "DistanceRamp", ramp = {{10,1},{70,0} } } ),
		},
		["additional_block_chance_against_projectiles_%_per_steel_charge"] = {
			mod("ProjectileBlockChance", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true }, { type = "Multiplier", var = "SteelWardCount", limit = 6 } ),
		},
		["fires_1_projectile_if_no_steel_ammo"] = {
			flag("NoAdditionalProjectiles", { type = "MultiplierThreshold", var = "SteelShardConsumed", threshold = 0, upper = true }),
		},
	},
#baseMod skill("radius", 28)
#mods

#skill SeismicTrap
#flags spell area trap duration
	preDamageFunc = function(activeSkill, output, breakdown)
		local skillCfg = activeSkill.skillCfg
		local skillData = activeSkill.skillData
		local skillPart = activeSkill.skillPart
		local skillModList = activeSkill.skillModList
		local t_insert = table.insert
		local s_format = string.format

		local baseInterval = skillData.repeatInterval
		local incFrequency = (1 + skillModList:Sum("INC", skillCfg, "TrapThrowingSpeed", "SeismicPulseFrequency") / 100)
		local moreFrequency = skillModList:More(skillCfg, "TrapThrowingSpeed", "SeismicPulseFrequency")
		local wavePulseRate = incFrequency * moreFrequency / baseInterval
		skillData.hitTimeOverride = 1 / wavePulseRate
		output.WavePulseRate = wavePulseRate
		local incDuration = (1 + skillModList:Sum("INC", skillCfg, "Duration") / 100)
		local moreDuration = skillModList:More(skillCfg, "Duration")
		local duration = skillData.duration * incDuration * moreDuration
		local pulses = math.floor(duration * wavePulseRate)
		output.PulsesPerTrap = pulses
		local effectiveDuration = pulses / wavePulseRate
		local cooldown = output.TrapCooldown
		local averageActiveTraps = effectiveDuration / cooldown
		output.AverageActiveTraps = averageActiveTraps
		local function hitChance(enemyRadius, areaDamageRadius, areaSpreadRadius) -- not to be confused with attack hit chance
			local damagingAreaRadius = areaDamageRadius + enemyRadius - 1	-- radius where area damage can land to hit the enemy;
			-- -1 because of two assumptions: PoE coordinates are integers and damage is not registered if the two areas only share a point or vertex. If either is not correct, then -1 is not needed.
			return math.min(damagingAreaRadius * damagingAreaRadius / (areaSpreadRadius * areaSpreadRadius), 1)
		end
		local enemyRadius = skillModList:Override(skillCfg, "EnemyRadius") or skillModList:Sum("BASE", skillCfg, "EnemyRadius")
		local waveRadius = output.AreaOfEffectRadiusSecondary
		local fullRadius = output.AreaOfEffectRadius
		local overlapChance = hitChance(enemyRadius, waveRadius, fullRadius)
		output.OverlapChance = overlapChance * 100
		if breakdown then
			breakdown.OverlapChance = { }
			t_insert(breakdown.OverlapChance, "Chance for individual wave to land within range to damage enemy:")
			t_insert(breakdown.OverlapChance, "^8= (area where wave can spawn to damage enemy) / (total area)")
			t_insert(breakdown.OverlapChance, "^8= (^7secondary radius^8 + ^7enemy radius^8 - 1) ^ 2 / ^7radius^8 ^ 2")
			t_insert(breakdown.OverlapChance, s_format("^8= (^7%d^8 +^7 %d^8 - 1) ^ 2 /^7 %d^8 ^ 2", waveRadius, enemyRadius, fullRadius))
			t_insert(breakdown.OverlapChance, s_format("^8=^7 %.3f^8%%", overlapChance * 100))
			breakdown.WavePulseRate = { }
			t_insert(breakdown.WavePulseRate, "Pulse rate:")
			t_insert(breakdown.WavePulseRate, s_format("%.2f ^8(base pulse rate)", 1 / baseInterval))
			t_insert(breakdown.WavePulseRate, s_format("* %.2f ^8(increased/reduced pulse frequency)", incFrequency))
			t_insert(breakdown.WavePulseRate, s_format("* %.2f ^8(more/less pulse frequency)", moreFrequency))
			t_insert(breakdown.WavePulseRate, s_format("= %.2f^8/s", wavePulseRate))
			breakdown.PulsesPerTrap = { }
			t_insert(breakdown.PulsesPerTrap, "Pulses per trap:")
			t_insert(breakdown.PulsesPerTrap, s_format("%.3f ^8(unrounded skill duration)", duration))
			t_insert(breakdown.PulsesPerTrap, s_format("* %.2f ^8(pulse rate)", wavePulseRate))
			t_insert(breakdown.PulsesPerTrap, s_format("= %.2f ^8pulses", duration * wavePulseRate))
			t_insert(breakdown.PulsesPerTrap, "^8rounded down")
			t_insert(breakdown.PulsesPerTrap, s_format("= %d ^8pulses", pulses))
			t_insert(breakdown.PulsesPerTrap, s_format("^8Next breakpoint: %d%% increased Trap Throwing Speed / %d%% increased Duration",
					math.ceil(100 * ((pulses + 1) * baseInterval / (duration * moreFrequency) - incFrequency)),
					math.ceil(100 * ((pulses + 1) / (wavePulseRate * skillData.duration * moreDuration) - incDuration))
			))
			t_insert(breakdown.PulsesPerTrap, s_format("^8Previous breakpoint: %d%% reduced Trap Throwing Speed / %d%% reduced Duration",
					-math.ceil(100 * (pulses * baseInterval / (duration * moreFrequency) - incFrequency) - 1),
					-math.ceil(100 * (pulses / (wavePulseRate * skillData.duration * moreDuration) - incDuration) - 1)
			))
			breakdown.AverageActiveTraps = { }
			t_insert(breakdown.AverageActiveTraps, "Average active traps, not considering stored cooldown uses:")
			t_insert(breakdown.AverageActiveTraps, s_format("%.2f^8 /^7 %.2f^8 (pulses / pulse rate = effective skill duration)", pulses, wavePulseRate))
			t_insert(breakdown.AverageActiveTraps, s_format("/ %.2f ^8(cooldown)", cooldown))
			t_insert(breakdown.AverageActiveTraps, s_format("= %.2f traps", averageActiveTraps))
		end
		local maxWaves = skillModList:Sum("BASE", skillCfg, "MaximumWaves")
		local dpsMultiplier = 1
		if skillPart == 2 then
			dpsMultiplier = maxWaves * overlapChance
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, "^8= ^7maximum waves^8 * ^7overlap chance^8")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d^8 *^7 %.2f^8", maxWaves, overlapChance))
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMultiplier))
			end
		elseif skillPart == 3 then
			dpsMultiplier = maxWaves
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d (maximum waves)", dpsMultiplier))
			end
		elseif skillPart == 4 then
			dpsMultiplier = averageActiveTraps
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.2f (average active traps)", dpsMultiplier))
			end
		elseif skillPart == 5 then
			dpsMultiplier = averageActiveTraps * maxWaves * overlapChance
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, "^8= ^7average active traps^8 * ^7maximum waves^8 * ^7overlap chance^8")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.2f^8 *^7 %d^8 *^7 %.2f", averageActiveTraps, maxWaves, overlapChance))
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMultiplier))
			end
		elseif skillPart == 6 then
			dpsMultiplier = averageActiveTraps * maxWaves
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, "^8= ^7average active traps^8 * ^7maximum waves")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.2f^8 *^7 %d", averageActiveTraps, maxWaves))
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMultiplier))
			end
		end
		if dpsMultiplier ~= 1 then
			skillData.dpsMultiplier = (skillData.dpsMultiplier or 1) * dpsMultiplier
			output.SkillDPSMultiplier = (output.SkillDPSMultiplier or 1) * dpsMultiplier
		end
	end,
	parts = {
		{
			name = "One wave hitting",
		},
		{
			name = "Average waves hitting configured size enemy",
		},
		{
			name = "All waves hitting",
		},
		{
			name = "Average active traps, one wave",
		},
		{
			name = "Average active traps, average waves",
		},
		{
			name = "Average active traps, all waves",
		},
	},
	statMap = {
		["base_skill_show_average_damage_instead_of_dps"] = {},
		["phys_cascade_trap_base_interval_duration_ms"] = {
			skill("repeatInterval", nil),
			div = 1000,
		},
		["phys_cascade_trap_number_of_cascades"] = {
			mod("MaximumWaves", "BASE", nil),
		},
		["seismic_trap_frequency_+%"] = {
			mod("SeismicPulseFrequency", "INC", nil),
		},
		["quality_display_phys_cascade_trap_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("radius", 18)
#baseMod skill("radiusLabel", "Large Burst:")
#baseMod skill("radiusSecondary", 9)
#baseMod skill("radiusSecondaryLabel", "Small Burst:")
#mods

#skill SeismicTrapAltX
#flags spell area trap
	preDamageFunc = function(activeSkill, output, breakdown)
		local skillCfg = activeSkill.skillCfg
		local skillData = activeSkill.skillData
		local skillPart = activeSkill.skillPart
		local skillModList = activeSkill.skillModList
		local t_insert = table.insert
		local s_format = string.format

		local function hitChance(enemyRadius, areaDamageRadius, areaSpreadRadius) -- not to be confused with attack hit chance
			local damagingAreaRadius = areaDamageRadius + enemyRadius - 1	-- radius where area damage can land to hit the enemy;
			-- -1 because of two assumptions: PoE coordinates are integers and damage is not registered if the two areas only share a point or vertex. If either is not correct, then -1 is not needed.
			return math.min(damagingAreaRadius * damagingAreaRadius / (areaSpreadRadius * areaSpreadRadius), 1)
		end
		local enemyRadius = skillModList:Override(skillCfg, "EnemyRadius") or skillModList:Sum("BASE", skillCfg, "EnemyRadius")
		local waveRadius = output.AreaOfEffectRadiusSecondary
		local fullRadius = output.AreaOfEffectRadius
		local overlapChance = hitChance(enemyRadius, waveRadius, fullRadius)
		output.OverlapChance = overlapChance * 100
		if breakdown then
			breakdown.OverlapChance = { }
			t_insert(breakdown.OverlapChance, "Chance for individual wave to land within range to damage enemy:")
			t_insert(breakdown.OverlapChance, "^8= (area where wave can spawn to damage enemy) / (total area)")
			t_insert(breakdown.OverlapChance, "^8= (^7secondary radius^8 + ^7enemy radius^8 - 1) ^ 2 / ^7radius^8 ^ 2")
			t_insert(breakdown.OverlapChance, s_format("^8= (^7%d^8 +^7 %d^8 - 1) ^ 2 /^7 %d^8 ^ 2", waveRadius, enemyRadius, fullRadius))
			t_insert(breakdown.OverlapChance, s_format("^8=^7 %.3f^8%%", overlapChance * 100))
		end
		local maxWaves = skillModList:Sum("BASE", skillCfg, "MaximumWaves")
		local dpsMultiplier = 1
		if skillPart == 2 then
			dpsMultiplier = maxWaves * overlapChance
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, "^8= ^7maximum waves^8 * ^7overlap chance^8")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d^8 *^7 %.2f^8", maxWaves, overlapChance))
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMultiplier))
			end
		elseif skillPart == 3 then
			dpsMultiplier = maxWaves
			if breakdown then
				breakdown.SkillDPSMultiplier = {}
				t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier")
				t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d (maximum waves)", dpsMultiplier))
			end
		end
		if dpsMultiplier ~= 1 then
			skillData.dpsMultiplier = (skillData.dpsMultiplier or 1) * dpsMultiplier
			output.SkillDPSMultiplier = (output.SkillDPSMultiplier or 1) * dpsMultiplier
		end
	end,
	parts = {
		{
			name = "One wave hitting",
		},
		{
			name = "Average waves hitting configured size enemy",
		},
		{
			name = "All waves hitting",
		},
	},
	statMap = {
		["base_skill_show_average_damage_instead_of_dps"] = {},
		["phys_cascade_trap_number_of_cascades"] = {
			mod("MaximumWaves", "BASE", nil),
		},
		["quality_display_phys_cascade_trap_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("radius", 18)
#baseMod skill("radiusLabel", "Large Burst:")
#baseMod skill("radiusSecondary", 9)
#baseMod skill("radiusSecondaryLabel", "Small Burst:")
#mods

#skill ShrapnelBallista
#flags attack projectile totem ballista
	preDamageFunc = function(activeSkill, output)
		if not activeSkill.skillModList:Flag(nil, "SequentialProjectiles") then
			activeSkill.skillData.dpsMultiplier = (activeSkill.skillData.dpsMultiplier or 1) * math.min(activeSkill.skillData.ShrapnelBallistaProjectileOverlap or (activeSkill.skillTypes[SkillType.Rain] and output.ProjectileCount or 1), output.ProjectileCount)
		end
		local splitCount = output.SplitCount or 0
		if splitCount > 0 then
			activeSkill.skillModList:NewMod("DPS", "MORE", splitCount * 100, "Split Return", 0, { type = "Condition", var = "ReturningProjectile" })
		end
	end,
#mods

#skill ShrapnelBallistaAltX
#flags attack projectile totem ballista
	preDamageFunc = function(activeSkill, output)
		if not activeSkill.skillModList:Flag(nil, "SequentialProjectiles") then
			activeSkill.skillData.dpsMultiplier = (activeSkill.skillData.dpsMultiplier or 1) * math.min(activeSkill.skillData.ShrapnelBallistaProjectileOverlap or (activeSkill.skillTypes[SkillType.Rain] and output.ProjectileCount or 1), output.ProjectileCount)
		end
		local splitCount = output.SplitCount or 0
		if splitCount > 0 then
			activeSkill.skillModList:NewMod("DPS", "MORE", splitCount * 100, "Split Return", 0, { type = "Condition", var = "ReturningProjectile" })
		end
	end,
	statMap = {
		["fires_1_projectile_if_no_steel_ammo"] = {
			flag("NoAdditionalProjectiles", { type = "MultiplierThreshold", var = "SteelShardConsumed", threshold = 0, upper = true }),
		},
	},
#mods

#skill SiegeBallista
#flags attack projectile totem ballista
	statMap = {
		["attack_speed_+%_per_maximum_totem"] = {
			mod("Speed", "INC", nil, ModFlag.Attack, 0, { type = "PerStat", stat = "ActiveTotemLimit" }),
		},
	},
#baseMod flag("ProjectileRain")
#mods

#skill SiegeBallistaAltX
#flags attack projectile totem ballista
#baseMod flag("ProjectileRain")
#mods

#skill SiegeBallistaAltY
#flags attack projectile totem ballista
	statMap = {
		["totem_fire_in_formation"] = {
			skill("totemFireOnce", true),
		},
		["active_skill_summon_X_totems_in_ring_override"] = {
			skill("dpsMultiplier", nil),
		},
	},
#mods

#skill SmokeMine
#flags spell mine area buff
	statMap = {
		["base_movement_velocity_+%"] = {
			mod("MovementSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
	},
#baseMod skill("radius", 18)
#mods

#skill SpectralShieldThrow
#flags attack projectile shieldAttack
	parts = {
		{
			name = "Shield",
		},
		{
			name = "Shards",
		},
	},
	statMap = {
		["thrown_shield_secondary_projectile_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
		},
		["primary_projectile_chains_+"] = {
			mod("ChainCountMax", "BASE", nil, 0, 0, { type = "SkillPart", skillPart = 1 }),
		},
		["off_hand_minimum_added_physical_damage_per_15_shield_armour_and_evasion_rating"] = {
			mod("PhysicalMin", "BASE", nil, 0, 0, { type = "Condition", var = "OffHandAttack" }, { type = "Condition", var = "ShieldThrowCrushNoArmourEvasion", neg = true }, { type = "PerStat", statList = { "ArmourOnWeapon 2", "EvasionOnWeapon 2" }, div = 15, }),
		},
		["off_hand_maximum_added_physical_damage_per_15_shield_armour_and_evasion_rating"] = {
			mod("PhysicalMax", "BASE", nil, 0, 0, { type = "Condition", var = "OffHandAttack" }, { type = "Condition", var = "ShieldThrowCrushNoArmourEvasion", neg = true }, { type = "PerStat", statList = { "ArmourOnWeapon 2", "EvasionOnWeapon 2" }, div = 15, }),
		},
	},
#mods

#skill SpectralShieldThrowAltX
#flags attack projectile shieldAttack
	parts = {
		{
			name = "Shield",
		},
		{
			name = "Shards",
		},
	},
	statMap = {
		["thrown_shield_secondary_projectile_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
		},
	},
#mods

#skill SpectralShieldThrowAltY
#flags attack projectile shieldAttack
	parts = {
		{
			name = "Shield",
		},
		{
			name = "Shards",
		},
	},
	statMap = {
		["thrown_shield_secondary_projectile_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
		},
		["stationary_shield_throw_firing_interval_ms"] = {
			skill("hitTimeOverride", nil, { type = "SkillPart", skillPart = 2 }),
			div = 1000,
		},
	},
#mods

#skill SpectralThrow
#flags attack projectile
#baseMod mod("PierceChance", "BASE", 100)
#mods

#skill SpectralThrowAltX
#flags attack projectile
#baseMod mod("PierceChance", "BASE", 100)
#mods

#skill SpectralThrowAltY
#flags attack projectile trap
#baseMod mod("PierceChance", "BASE", 100)
#mods

#skill VaalSpectralThrow
#flags attack projectile vaal
	statMap = {
		["base_number_of_projectiles_in_spiral_nova"] = {
			mod("ProjectileCount", "BASE", nil),
		},
	},
#mods

#skill ToxicRain
#flags attack projectile area duration
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.dpsMultiplier = math.min(activeSkill.skillData.podOverlapMultiplier or 1, output.ProjectileCount)
	end,
#baseMod skill("dotIsArea", true)
#baseMod flag("DotCanStack")
#baseMod flag("OneShotProj")
#baseMod skill("radius", 18)
#baseMod skill("radiusLabel", "Pod Area:")
#mods

#skill ToxicRainAltX
#flags attack projectile area duration
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.dpsMultiplier = math.min(activeSkill.skillData.podOverlapMultiplier or 1, output.ProjectileCount)
	end,
#baseMod flag("OneShotProj")
#baseMod skill("radius", 18)
#baseMod skill("radiusLabel", "Pod Area:")
#mods

#skill ToxicRainAltY
#flags attack projectile area duration
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.dpsMultiplier = math.min(activeSkill.skillData.podOverlapMultiplier or 1, output.ProjectileCount)
	end,
	statMap = {
		["toxic_rain_spores_apply_withered"] = {
			flag("Condition:CanWither"),
		},
	},
#baseMod skill("dotIsArea", true)
#baseMod flag("DotCanStack")
#baseMod flag("OneShotProj")
#baseMod skill("radius", 18)
#baseMod skill("radiusLabel", "Pod Area:")
#mods

#skill SpectralHelix
#flags attack projectile bounce
	statMap = {
		["spectral_spiral_weapon_base_number_of_bounces"] = {
			mod("BounceCount", "BASE", nil),
		},
	},
#baseMod flag("NoAdditionalProjectiles")
#baseMod flag("AdditionalProjectilesAddBouncesInstead")
#mods

#skill SpectralHelixAltY
#flags attack projectile bounce trap
	statMap = {
		["spectral_spiral_weapon_base_number_of_bounces"] = {
			mod("BounceCount", "BASE", nil),
		},
	},
#baseMod flag("NoAdditionalProjectiles")
#baseMod flag("AdditionalProjectilesAddBouncesInstead")
#mods

#skill SplitArrow
#flags attack projectile
#mods

#skill SplitArrowAltX
#flags attack projectile
#mods

#skill SplittingSteel
#flags attack projectile area
#mods

#skill SplittingSteelAltX
#flags attack projectile area
#mods

#skill SummonIceGolem
#flags spell minion golem permanentMinion
	minionList = {
		"SummonedIceGolem",
	},
	statMap = {
		["ice_golem_grants_critical_strike_chance_+%"] = {
			mod("CritChance", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
		["ice_golem_grants_accuracy_rating_+"] = {
			mod("Accuracy", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
		},
	},
#baseMod skill("allowTotemBuff", true)
#baseMod flag("Condition:HaveColdGolem", { type = "GlobalEffect", effectType = "Buff" })
#mods

#skill SummonIceGolemAltX
#flags spell minion golem permanentMinion
	minionList = {
		"SummonedIceGolem",
	},
#baseMod skill("allowTotemBuff", true)
#baseMod flag("Condition:HaveColdGolem", { type = "GlobalEffect", effectType = "Buff" })
#mods

#skill SummonIceGolemAltY
#flags spell minion golem permanentMinion
	minionList = {
		"SummonedIceGolem",
	},
#baseMod skill("allowTotemBuff", true)
#baseMod flag("Condition:HaveColdGolem", { type = "GlobalEffect", effectType = "Buff" })
#mods

#skill TemporalChains
#flags spell curse area duration hex
	statMap = {
		["temporal_chains_action_speed_+%_final"] = {
			mod("TemporalChainsActionSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Curse" }, { type = "Condition", var = "RareOrUnique", neg = true }),
		},
		["buff_time_passed_+%_other_than_temporal_chains"] = {
			mod("BuffExpireFaster", "MORE", nil, 0, 0, { type = "GlobalEffect", effectType = "Curse" }),
		},
		["curse_effect_+%_final_vs_players"] = {
			mod("CurseEffectAgainstPlayer", "MORE", nil),
		},
		["temporal_chains_action_speed_+%_vs_rare_or_unique_final"] = {
			mod("TemporalChainsActionSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Curse" }, { type = "Condition", var = "RareOrUnique" }),
		},
	},
#baseMod skill("debuff", true)
#baseMod skill("radius", 22)
#mods

#skill TornadoShot
#flags attack projectile
	parts = {
		{
			name = "Single Projectile",
		},
		{
			name = "Combined Average Projectiles",
		},
	},
	preDamageFunc = function(activeSkill, output)
		if activeSkill.skillPart == 2 and (output.ReturnChance or 0) == 0 then
			local averageSecondaryProjectiles = output.ProjectileCount + (output.SplitCount or 0)
			-- if barrage then only shoots 1 projectile at a time, but those can still split and still releases at least 1 secondary projectile
			if activeSkill.skillModList:Flag(nil, "SequentialProjectiles") and not activeSkill.skillModList:Flag(nil, "OneShotProj") and not activeSkill.skillModList:Flag(nil,"NoAdditionalProjectiles") and not activeSkill.skillModList:Flag(nil, "TriggeredBySnipe") then
				averageSecondaryProjectiles = 1 + (output.SplitCount or 0)
			end
			-- default to 20% per secondary projectile, so 60% base, and 80% with helm enchant
			local chanceForSecondaryProjectilesToHit = math.min((activeSkill.skillData.tornadoShotSecondaryHitChance or (20 * activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "tornadoShotSecondaryProjectiles"))) / 100, 1)
			activeSkill.skillData.dpsMultiplier = (activeSkill.skillData.dpsMultiplier or 1) * (1 + chanceForSecondaryProjectilesToHit * averageSecondaryProjectiles)
		end
	end,
	statMap = {
		["tornado_shot_num_of_secondary_projectiles"] = {
			mod("tornadoShotSecondaryProjectiles", "BASE", nil),
		},
	},
#mods

#skill TornadoShotAltX
#flags attack projectile
#mods

#skill Unearth
#flags spell projectile corpse
	statMap = {
		["unearth_base_corpse_level"] = {
			mod("CorpseLevel", "BASE", nil),
		},
	},
#baseMod skill("corpseMonsterVariety", "Bone Archer")
#mods

#skill VenomGyre
#flags attack projectile
	parts = {
		{
			name = "Outgoing Projectile",
		},
		{
			name = "Returning Projectile",
		},
	},
#baseMod flag("Condition:ReturningProjectile", { type = "SkillPart", skillPart = 2 })
#mods

#skill VaalVenomGyre
#flags attack projectile duration
#mods

#skill ViperStrike
#flags attack melee duration
	statMap = {
		["viper_strike_dual_wield_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, 0, { type = "Condition", var = "DualWielding" }),
		},
		["viper_strike_dual_wield_attack_speed_+%_final"] = {
			mod("Speed", "MORE", nil, ModFlag.Attack, 0, { type = "Condition", var = "DualWielding" }),
		},
	},
#baseMod skill("poisonIsSkillEffect", true)
#mods

#skill ViperStrikeAltX
#flags attack melee duration
	statMap = {
		["active_skill_poison_damage_+%_final"] = {
			mod("Damage", "MORE", nil, 0, KeywordFlag.Poison),
		},
		["quality_display_active_skill_poison_damage_final_is_gem"] = {
			-- Display only
		},
	},
#baseMod skill("poisonIsSkillEffect", true)
#mods

#skill VolatileDead
#flags spell area
	parts = {
		{
			name = "Spell",
			spell = true,
			cast = false,
		},
		{
			name = "Corpse Explosion",
			spell = false,
			cast =  true,
		},
	},
	statMap = {
		["spell_minimum_base_fire_damage"] = {
			skill("FireMin", nil, { type = "SkillPart", skillPart = 1 }),
		},
		["spell_maximum_base_fire_damage"] = {
			skill("FireMax", nil, { type = "SkillPart", skillPart = 1 }),
		},
	},
#baseMod skill("explodeCorpse", true, { type = "SkillPart", skillPart = 2 })
#baseMod skill("radiusLabel", "Orb Explosion:")
#baseMod skill("radiusSecondaryLabel", "Corpse Explosion:")
#mods

#skill VolatileDeadAltX
#flags spell area
	parts = {
		{
			name = "Spell",
			spell = true,
			cast = false,
		},
		{
			name = "Corpse Explosion",
			spell = false,
			cast =  true,
		},
	},
	statMap = {
		["spell_minimum_base_fire_damage"] = {
			skill("FireMin", nil, { type = "SkillPart", skillPart = 1 }),
		},
		["spell_maximum_base_fire_damage"] = {
			skill("FireMax", nil, { type = "SkillPart", skillPart = 1 }),
		},
	},
#baseMod skill("explodeCorpse", true, { type = "SkillPart", skillPart = 2 })
#baseMod skill("radiusLabel", "Orb Explosion:")
#baseMod skill("radiusSecondaryLabel", "Corpse Explosion:")
#mods

#skill VolatileDeadAltY
#flags spell area
	parts = {
		{
			name = "Spell",
			spell = true,
			cast = false,
		},
		{
			name = "Corpse Explosion",
			spell = false,
			cast =  true,
		},
	},
	statMap = {
		["spell_minimum_base_fire_damage"] = {
			skill("FireMin", nil, { type = "SkillPart", skillPart = 1 }),
		},
		["spell_maximum_base_fire_damage"] = {
			skill("FireMax", nil, { type = "SkillPart", skillPart = 1 }),
		},
	},
#baseMod skill("explodeCorpse", true, { type = "SkillPart", skillPart = 2 })
#baseMod skill("radiusLabel", "Orb Explosion:")
#baseMod skill("radiusSecondaryLabel", "Corpse Explosion:")
#mods

#skill WhirlingBlades
#flags attack melee
#mods

#skill WildStrike
#flags attack melee projectile chaining area
	parts = {
		{
			name = "Fire hit",
			melee = true,
			projectile = false,
			chaining = false,
			area = false,
		},
		{
			name = "Fire explosion",
			melee = false,
			projectile = false,
			chaining = false,
			area = true,
		},
		{
			name = "Lightning hit",
			melee = true,
			projectile = false,
			chaining = false,
			area = false,
		},
		{
			name = "Lightning bolt",
			melee = false,
			projectile = false,
			chaining = true,
			area = false,
		},
		{
			name = "Cold hit",
			melee = true,
			projectile = false,
			chaining = false,
			area = false,
		},
		{
			name = "Icy wave",
			melee = false,
			projectile = true,
			chaining = false,
			area = false,
		},
	},
	statMap = {
		["elemental_strike_physical_damage_%_to_convert"] = {
			mod("SkillPhysicalDamageConvertToFire", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList =  { 1, 2 } }),
			mod("SkillPhysicalDamageConvertToLightning", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList =  { 3, 4 } }),
			mod("SkillPhysicalDamageConvertToCold", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList =  { 5, 6 } }),
		},
	},
#baseMod skill("radius", 24, { type = "SkillPart", skillPart = 2 })
#mods

#skill WildStrikeAltX
#flags attack melee projectile chaining area
	parts = {
		{
			name = "Fire hit",
			melee = true,
			projectile = false,
			chaining = false,
			area = false,
		},
		{
			name = "Fire explosion",
			melee = false,
			projectile = false,
			chaining = false,
			area = true,
		},
		{
			name = "Lightning hit",
			melee = true,
			projectile = false,
			chaining = false,
			area = false,
		},
		{
			name = "Lightning bolt",
			melee = false,
			projectile = false,
			chaining = true,
			area = false,
		},
		{
			name = "Cold hit",
			melee = true,
			projectile = false,
			chaining = false,
			area = false,
		},
		{
			name = "Icy wave",
			melee = false,
			projectile = true,
			chaining = false,
			area = false,
		},
	},
	statMap = {
		["elemental_strike_physical_damage_%_to_convert"] = {
			mod("SkillPhysicalDamageConvertToFire", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList =  { 1, 2 } }),
			mod("SkillPhysicalDamageConvertToLightning", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList =  { 3, 4 } }),
			mod("SkillPhysicalDamageConvertToCold", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList =  { 5, 6 } }),
		},
	},
#baseMod skill("radius", 24, { type = "SkillPart", skillPart = 2 })
#mods

#skill WitheringStep
#flags spell duration
	statMap = {
		["slither_wither_stacks"] = {
			flag("Condition:CanWither"),
		},
		["quality_display_withering_step_is_gem"] = {
			-- Display only
		},
	},
#baseMod flag("Condition:CanBeElusive", { type = "GlobalEffect", effectType = "Buff" })
#baseMod skill("radius", 26)
#mods

#skill PoisonousConcoction
#flags attack area projectile
	parts = {
		{
			name = "No Flask",
		},
		{
			name = "Life",
		},
	},
	preDamageFunc = function(activeSkill, output)
		local multiplier = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "ChaosPerLifeFlaskPercent") or 0
		local addedFromFlask = (output.LifeFlaskRecovery or 0) * (multiplier / 100)
		activeSkill.skillModList:NewMod("ChaosMin", "BASE", addedFromFlask, "Life Flask charges consumed")
		activeSkill.skillModList:NewMod("ChaosMax", "BASE", addedFromFlask, "Life Flask charges consumed")
	end,
	statMap = {
		["flask_throw_added_chaos_damage_%_of_flask_life_to_recover"] = {
			mod("ChaosPerLifeFlaskPercent", "BASE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
		},
	},
#mods

#skill PoisonousConcoctionAltX
#flags attack area projectile
	parts = {
		{
			name = "No Flask",
		},
		{
			name = "Life",
		},
	},
	preDamageFunc = function(activeSkill, output)
		local multiplier = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "ChaosPerLifeFlaskPercent") or 0
		local addedFromFlask = (output.LifeFlaskRecovery or 0) * (multiplier / 100)
		activeSkill.skillModList:NewMod("ChaosMin", "BASE", addedFromFlask, "Life Flask charges consumed")
		activeSkill.skillModList:NewMod("ChaosMax", "BASE", addedFromFlask, "Life Flask charges consumed")
	end,
	statMap = {
		["flask_throw_added_chaos_damage_%_of_flask_life_to_recover"] = {
			mod("ChaosPerLifeFlaskPercent", "BASE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
		},
	},
#baseMod mod("DPS", "MORE", 100, 0, 0, { type = "PerStat", stat = "ChainMax" })
#mods

#skill Snipe
#flags attack projectile channelRelease
	statMap = {
		["snipe_max_stacks"] = {
			mod("Multiplier:SnipeStagesMax", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true }),
		},
		["quality_display_snipe_is_gem"] = {
			-- Display only
		},
	},
#mods

#skill ChannelledSnipeSupport
#baseMod flag("TriggeredBySnipe")
#mods

#skill TemporalRift
#flags spell
	statMap = {
		["debuff_time_passed_+%"] = {
			mod("SelfDebuffExpirationRate", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" })
		},
	},
#mods

#skill Thunderstorm
#flags attack projectile area duration
	parts = {
		{
			name = "Projectile",
		},
		{
			name = "Storm Explosion",
			stages = true,
		},
	},
	statMap = {
		["windstorm_storm_hit_damage_+%_final_on_detonation"] = {
			mod("Damage", "MORE", nil, 0, bit.bor(KeywordFlag.Hit, KeywordFlag.Ailment), { type = "SkillPart", skillPart = 2 } )
		},
		["windstorm_storm_maximum_stages"] = {
			mod("Multiplier:ThunderstormMaxStages", "BASE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
		},
		["windstorm_storm_area_of_effect_+%_final_per_stage"] = {
			mod("AreaOfEffect", "MORE", nil, 0, 0, { type = "Multiplier", var = "ThunderstormStage" }, { type = "SkillPart", skillPart = 2 }),
		},
		["base_windstorm_storm_stage_gained_per_X_ms"] = {
			skill("hitTimeOverride", nil, { type = "Multiplier", var = "ThunderstormStage" }, { type = "SkillPart", skillPart = 2 }),
			div = 1000,
		},
		["base_skill_show_average_damage_instead_of_dps"] = {
			skill("showAverage", true,  { type = "SkillPart", skillPart = 2 }),
		},
	},
#mods

#skill ThunderstormMiniTornados
#flags attack duration
	parts = {
		{
			name = "Projectile",
			projectile = true,
		},
		{
			name = "Explosion",
			area = true,
		},
	},
#mods

#skill Tornado
#flags spell duration physical area
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.hitTimeOverride = activeSkill.skillData.damageInterval
	end,
	statMap = {
		["tornado_base_damage_interval_ms"] = {
			skill("damageInterval", nil ),
			div = 1000,
		},
	},
#mods

#skill TornadoAltY
#flags spell duration physical area
	preDamageFunc = function(activeSkill, output)
		activeSkill.skillData.hitTimeOverride = activeSkill.skillData.damageInterval
		activeSkill.skillData.dpsMultiplier = (activeSkill.skillData.dpsMultiplier or 1) * activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "Multiplier:TornadoofElementalTurbulenceStage")
	end,
	parts = {
		{
			name = "Fire",
			stages = true,
		},
		{
			name = "Lightning",
			stages = true,
		},
		{
			name = "Cold",
			stages = true,
		},
	},
	statMap = {
		["tornado_base_damage_interval_ms"] = {
			skill("damageInterval", nil ),
			div = 1000,
		},
		["elemental_strike_physical_damage_%_to_convert"] = {
			mod("SkillPhysicalDamageConvertToFire", "BASE", nil, 0, 0, { type = "SkillPart", skillPart = 1 }),
			mod("SkillPhysicalDamageConvertToLightning", "BASE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }),
			mod("SkillPhysicalDamageConvertToCold", "BASE", nil, 0, 0, { type = "SkillPart", skillPart = 3 }),
		},
		["number_of_tornados_allowed"] = {
			mod("Multiplier:TornadoofElementalTurbulenceMaxStages", "BASE", nil),
		},
	},
#mods

#skill IntuitiveLink
#flags spell duration
	statMap = {
		["display_trigger_link"] = {
			-- Display only
		},
	},
#mods

#skill SupportIntuitiveLink
	statMap = {
		["trigger_on_trigger_link_target_hit"] = {
			-- Display only
		},
		["support_trigger_link_damage_+%_final"] = {
			mod("Damage", "MORE", nil),
		},
	},
#mods

#skill VampiricLink
#flags spell duration
	statMap = {
		["life_leech_is_applied_to_remora_link_targets_instead"] = {
			flag("CannotLeechLife", { type = "GlobalEffect", effectType = "Buff" }), -- this just disables your leech for now
			flag("MaximumLifeLeechIsEqualToParent", { type = "GlobalEffect", effectType = "Link" }),
		},
		["remora_link_grants_maximum_life_leech_rate_%_per_minute"] = {
			mod("MaxLifeLeechRate", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }),
			div = 60,
		},
	},
#mods

#skill QuickstepHardMode
#flags movement travel
#mods
