-- Base Attack --

Base_Attack = Base_Skill:New({

	GetPierce = function(self, Source)
		return Source.Pierce
	end,

	GetDamageType = function(self, Object)
		local Weapon = Object.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND1)
		if Weapon ~= nil then
			return Weapon.DamageType
		end

		return self.Item.DamageType
	end,

	GenerateDamage = function(self, Level, Source, Target)
		return Source.GenerateDamage()
	end,

	ModifiedGenerateDamage = function(self, Level, Source, Target)
		local Damage = Source.GenerateDamage()

		-- Deal more damage to enemies with a certain debuff
		for i = 1, #Target.StatusEffects do
			local Effect = Target.StatusEffects[i]
			if Effect.Buff == self.ModifiedDamageBuff then
				Damage = math.floor(Damage * ((100 + Effect.Modifier) * 0.01))
				break
			end
		end

		return Damage
	end,

	GetDamageMultiplier = function(self, Source)
		return 1.0
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		return false
	end,

	Use = function(self, Level, Duration, Source, Target, Result)
		if Battle_ResolveDamage(self, Level, Source, Target, Result) then
			self:Proc(Random.GetInt(1, 100), Level, Duration, Source, Target, Result)
			WeaponProc(Source, Target, Result, false)
		end

		return Result
	end
})

-- Base Ghost Attack
Base_GhostAttack = Base_Attack:New({

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Target.DamageBlock = 0
		local Hit = Battle_ResolveDamage(self, Level, Source, Target, Result)

		return Result
	end,
})

-- MONSTER SKILLS --

-- Monster attack --

Skill_MonsterAttack = Base_Attack:New({

	PlaySound = function(self)
		Audio.Play("bash" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Crow attack --

Skill_CrowAttack = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 15 then
			Result.Target.Buff = Buff_Blinded.Pointer
			Result.Target.BuffLevel = Level
			Result.Target.BuffDuration = 5
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("swoop" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Slime attack --

Skill_SlimeAttack = Base_Attack:New({

	PlaySound = function(self)
		Audio.Play("slime" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Ant attack --

Skill_AntAttack = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 15 then
			Result.Target.Buff = Buff_Poisoned.Pointer
			Result.Target.BuffLevel = math.floor(Level * Source.PoisonPower * 0.01)
			Result.Target.BuffDuration = 2
			Result.Target.BuffModifier = 25
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("crunch" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Crab attack --

Skill_CrabAttack = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 15 then
			Result.Target.Buff = Buff_Bleeding.Pointer
			Result.Target.BuffLevel = math.floor(Level * Source.BleedPower * 0.01)
			Result.Target.BuffDuration = 3
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("crab" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Spider bite --

Skill_SpiderBite = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 15 then
			Result.Target.Buff = Buff_Slowed.Pointer
			Result.Target.BuffLevel = Level
			Result.Target.BuffDuration = 5
			Result.Target.BuffModifier = 0
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("spider0.ogg")
	end,
})

-- Arach bite --

Skill_ArachBite = Skill_SpiderBite:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		Result.Target.Buff = Buff_Slowed.Pointer
		Result.Target.BuffLevel = Level
		Result.Target.BuffDuration = 5
		Result.Target.BuffModifier = 0

		return true
	end,
})

-- Sol bite --

Skill_SolBite = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		Result.Target.Buff = Buff_Vulnerable.Pointer
		Result.Target.BuffLevel = Level
		Result.Target.BuffDuration = 5

		return true
	end,

	PlaySound = function(self)
		Audio.Play("rupture0.ogg")
	end,
})

-- Fang bite --

Skill_FangBite = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 15 then
			Result.Target.Buff = Buff_Bleeding.Pointer
			Result.Target.BuffLevel = math.floor(Level * Source.BleedPower * 0.01)
			Result.Target.BuffDuration = 5
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("bat0.ogg")
	end,
})

-- Venom bite --

Skill_VenomBite = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 15 then
			Result.Target.Buff = Buff_Poisoned.Pointer
			Result.Target.BuffLevel = math.floor(Level * Source.PoisonPower * 0.01)
			Result.Target.BuffDuration = 10
			Result.Target.BuffModifier = 35
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("bat0.ogg")
	end,
})

-- Sting --

Skill_Sting = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 15 then
			Result.Target.Buff = Buff_Stunned.Pointer
			Result.Target.BuffLevel = 1
			Result.Target.BuffDuration = 1
			return true
		elseif Roll <= 30 then
			Result.Target.Buff = Buff_Poisoned.Pointer
			Result.Target.BuffLevel = math.floor(Level * Source.PoisonPower * 0.01)
			Result.Target.BuffDuration = 5
			Result.Target.BuffModifier = 50
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("sting" .. Random.GetInt(0, 2) .. ".ogg", 0.65)
	end,
})

-- Ghost attack --

Skill_GhostAttack = Base_GhostAttack:New({

	PlaySound = function(self)
		Audio.Play("ghost" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Swoop attack --

Skill_Swoop = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 75 then
			Result.Target.Buff = Buff_Stunned.Pointer
			Result.Target.BuffLevel = 1
			Result.Target.BuffDuration = 3
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("multiswoop0.ogg")
	end,
})

-- Pincer attack --

Skill_PincerAttack = Base_GhostAttack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 75 then
			Result.Target.Buff = Buff_Bleeding.Pointer
			Result.Target.BuffLevel = math.floor(Level * Source.BleedPower * 0.01)
			Result.Target.BuffDuration = 5
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("multislash0.ogg")
	end,
})

-- Chew attack --

Skill_ChewAttack = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 75 then
			Result.Source.Health = -Result.Target.Health
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("grunt" .. Random.GetInt(0, 2) .. ".ogg")
	end,
})

-- Swamp attack --

Skill_SwampAttack = Base_Attack:New({

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= 30 then
			Result.Target.Buff = Buff_Slowed.Pointer
			Result.Target.BuffLevel = Level
			Result.Target.BuffDuration = 5
			Result.Target.BuffModifier = 0
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("sludge0.ogg")
	end,
})

-- Skeleton attack --

Skill_SkeletonAttack = Base_Attack:New({

	GenerateDamage = Base_Attack.ModifiedGenerateDamage,
	ModifiedDamageBuff = Buff_Poisoned,

	PlaySound = function(self)
		Audio.Play("bones" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Demon attack --

Skill_DemonAttack = Base_Attack:New({

	AttributeName = "Fire",
	Duration = Growth_Linear:New({ A = 0, B = Game.FireDuration }),

	GenerateDamage = function(self, Level, Source, Target)
		local Damage = Source.GenerateDamage()

		-- Deal more damage to burning enemies
		for i = 1, #Target.StatusEffects do
			local Effect = Target.StatusEffects[i]
			if Effect.Buff == Buff_Burning then
				local Multiplier = Buff_Burning:GetDemonDamage(Effect.Stacks) + 1
				Damage = math.floor(Damage * Multiplier)
				break
			end
		end

		return Damage
	end,

	PlaySound = function(self)
		Audio.Play("demon" .. Random.GetInt(0, 1) .. ".ogg")
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		Result.Target.Buff = Buff_Burning.Pointer
		Result.Target.BuffLevel = Source.BuffLevel
		Result.Target.BuffDuration = self:GetDuration(Source, Level, true)

		return true
	end,
})

-- Ice Imp attack --

Skill_IceImpAttack = Base_Attack:New({

	AttributeName = "Cold",
	Duration = Growth_Linear:New({ A = 0, B = Game.ColdDuration }),
	BuffModifier = Growth_Linear:New({ A = 90 / 49.0, B = 10 }),
	GenerateDamage = Base_Attack.ModifiedGenerateDamage,
	ModifiedDamageBuff = Buff_Slowed,
	MaxSlow = 50,

	PlaySound = function(self)
		Audio.Play("demon" .. Random.GetInt(0, 1) .. ".ogg")
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		Result.Target.Buff = Buff_Slowed.Pointer
		Result.Target.BuffLevel = math.min(Source.BuffLevel, self.MaxSlow)
		Result.Target.BuffDuration = self:GetDuration(Source, Level, true)
		Result.Target.BuffModifier = self.BuffModifier:Result(Level)

		return true
	end,
})

-- PLAYER SKILLS --

-- Attack --

Skill_Attack = Base_Attack:New({

	TargetCount = Growth_Linear:New({ A = 1 / 49.0, B = 1 }),
	Chance = Growth_Linear:New({ A = 10 / 49.0, B = 10 }),
	Damage = Growth_Linear:New({ A = 100 / 49.0, B = 100 }),
	CritMultiplier = Growth_Linear:New({ A = 1 / 49.0, B = 2 }),

	GetDamage = function(self, Level)
		return self.Damage:Result(Level)
	end,

	GetCritMultiplier = function(self, Level)
		return self.CritMultiplier:Result(Level, RoundDown2)
	end,

	GetChance = function(self, Source, Level)
		return self.Chance:Result(Level)
	end,

	GetInfo = function(self, Source, Item)
		local DamageValue = self:GetDamage(Item.Level) .. "%"
		local CritValue = self:GetCritMultiplier(Item.Level) .. "x"
		if Item.MoreInfo then
			DamageValue = Source.GetAverageDamage() * self:GetDamage(Item.Level) * 0.01
			CritValue = FormatSI(DamageValue * self:GetCritMultiplier(Item.Level), true) .. " avg"
			DamageValue = FormatSI(DamageValue, true) .. " avg"
		end

		return
			"Attack " .. self:GetTargetText(Source, Item) .. " for [c green]" .. DamageValue .. "[c white] weapon damage\n" ..
			"[c green]" .. self:GetChance(Source, Item.Level) .. "%[c white] chance to deal [c green]" .. CritValue .. "[c white] damage"
	end,

	PlaySound = function(self)
		Audio.Play("slash" .. Random.GetInt(0, 1) .. ".ogg")
	end,

	GenerateDamage = function(self, Level, Source, Target)
		local Damage = math.floor(Source.GenerateDamage() * self:GetDamage(Level) * 0.01)
		local Crit = false
		if Random.GetInt(1, 100) <= self:GetChance(Source, Level) then
			Damage = math.floor(Damage * self:GetCritMultiplier(Level))
			Crit = true
		end

		return Damage, Crit
	end,
})

-- Backstab --

Skill_Backstab = Base_Attack:New({

	TargetCount = Growth_Linear:New({ A = 1 / 49.0, B = 1 }),
	StaminaGain = Growth_Linear:New({ A = 50 / 49.0, B = 50 }),
	Damage = Growth_Linear:New({ A = 900 / 49.0, B = 300 }),
	BaseDamage = 50,

	GetInfo = function(self, Source, Item)
		local TextColor = self:CanUse(Item.Level, Source, nil) and "yellow" or "red"
		local BaseDamageValue = self.BaseDamage .. "%"
		local Damage = self.Damage:Result(Item.Level)
		local DamageValue = Damage .. "%"
		if Item.MoreInfo then
			BaseDamageValue = FormatSI(Source.GetAverageDamage() * self.BaseDamage * 0.01, true) .. " avg"
			DamageValue = FormatSI(Source.GetAverageDamage() * Damage * 0.01, true) .. " avg"
		end

		return
			"Attack " .. self:GetTargetText(Source, Item) .. " for [c green]" .. BaseDamageValue .. "[c white] weapon damage\n" ..
			"Deal [c green]" .. DamageValue .. "[c white] damage to stunned enemies\n" ..
			"Gain [c green]" .. self.StaminaGain:Result(Item.Level) .. "%[c white] [c yellow]stamina[c white] for a kill\n\n" ..
			"[c " .. TextColor .. "]Can only use with off-hand weapons"
	end,

	CanUse = function(self, Level, Source)
		local WeaponMain = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND1)
		if WeaponMain == nil then
			local WeaponOff = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND2)
			if WeaponOff ~= nil and WeaponOff.Type == ITEM_OFFHAND then
				return true
			end

			return false
		end

		return WeaponMain.Type == ITEM_OFFHAND
	end,

	GenerateDamage = function(self, Level, Source, Target)
		local Damage = Source.GenerateDamage()

		-- Check for stunned
		for i = 1, #Target.StatusEffects do
			local Effect = Target.StatusEffects[i]
			if Effect.Buff == Buff_Stunned then
				Damage = math.floor(Damage * self.Damage:Result(Level) * 0.01)
				return Damage, true
			end
		end

		Damage = math.floor(Damage * self.BaseDamage * 0.01)
		return Damage, false
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Target.Health + Result.Target.Health <= 0 then
			Result.Source.Stamina = self.StaminaGain:Result(Level) * 0.01
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("gash0.ogg")
	end,
})

-- Blade Dance --

Skill_BladeDance = Base_Attack:New({

	AttributeName = "Bleed",
	TargetCount = Growth_Linear:New({ A = 4 / 49.0, B = 4 }),
	Duration = Growth_Linear:New({ A = 0, B = Game.BleedDuration }),
	Damage = Growth_Linear:New({ A = 125 / 49.0, B = 100 }),
	Bleed = Growth_Polynomial:New({ E = 2, A = 2, B = 20, C = 40 }),

	CanUse = function(self, Level, Source)
		local WeaponMain = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND1)
		if WeaponMain == nil then
			return false
		end

		local WeaponOff = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND2)
		if WeaponOff == nil then
			return false
		end

		return WeaponMain.Type == ITEM_OFFHAND and WeaponOff.Type == ITEM_OFFHAND
	end,

	GetDamage = function(self, Level)
		return self.Damage:Result(Level)
	end,

	GenerateDamage = function(self, Level, Source, Target)
		return math.floor(Source.GenerateDamage() * self:GetDamage(Level) * 0.01)
	end,

	GetBleedLevel = function(self, Source, Level)
		return self.Bleed:ModifiedResult(Level, Source.BleedPower * 0.01, 0)
	end,

	GetBleedDamage = function(self, Source, Level)
		return self:GetDuration(Source, Level, true) * self:GetBleedLevel(Source, Level)
	end,

	GetInfo = function(self, Source, Item)
		local TextColor = self:CanUse(Item.Level, Source, nil) and "yellow" or "red"
		local DamageValue = self:GetDamage(Item.Level) .. "%"
		if Item.MoreInfo then
			DamageValue = FormatSI(Source.GetAverageDamage() * self:GetDamage(Item.Level) * 0.01, true) .. " avg"
		end

		local BleedDamageValue
		if Item.MoreInfo then
			BleedDamageValue = FormatSI(self:GetBleedLevel(Source, Item.Level), true) .. "[c white] stacking bleed DPS"
		else
			BleedDamageValue = FormatSI(self:GetBleedDamage(Source, Item.Level), true) .. "[c white] stacking bleed damage over [c green]" .. self:GetDuration(Source, Item.Level, true) .. "[c white] seconds"
		end

		return
			"Whirl in a dance of blades, hitting " .. self:GetTargetText(Source, Item) .. " for [c green]" .. DamageValue ..
			"[c white] weapon damage and causing [c green]" .. BleedDamageValue .. "\n\n" ..
			"[c " .. TextColor .. "]Requires two off-hand weapons"
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		Result.Target.Buff = Buff_Bleeding.Pointer
		Result.Target.BuffLevel = self:GetBleedLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Level, true)

		return true
	end,

	PlaySound = function(self)
		Audio.Play("gash0.ogg")
	end,
})

-- Cleave --

Skill_Cleave = Base_Attack:New({

	TargetCount = Growth_Linear:New({ A = 1 / 49.0, B = 3 }),
	Damage = Growth_Linear:New({ A = 85 / 49.0, B = 50 }),

	CanUse = function(self, Level, Source)
		local WeaponMain = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND1)
		if WeaponMain == nil then
			return false
		end

		local WeaponOff = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND2)
		if WeaponOff == nil then
			return WeaponMain.Type ~= ITEM_OFFHAND
		end

		return WeaponMain.Type ~= ITEM_OFFHAND and WeaponOff.Type ~= ITEM_OFFHAND
	end,

	GetDamage = function(self, Level)
		return self.Damage:Result(Level)
	end,

	GenerateDamage = function(self, Level, Source, Target)
		return math.floor(Source.GenerateDamage() * self:GetDamage(Level) * 0.01)
	end,

	GetInfo = function(self, Source, Item)
		local TextColor = self:CanUse(Item.Level, Source, nil) and "yellow" or "red"
		local DamageValue
		if Item.MoreInfo then
			DamageValue = FormatSI(Source.GetAverageDamage() * self:GetDamage(Item.Level) * 0.01, true) .. " avg"
		else
			DamageValue = self:GetDamage(Item.Level) .. "%"
		end

		return
			"Swing your weapon and hit " .. self:GetTargetText(Source, Item) .. " for [c green]" .. DamageValue .. "[c white] weapon damage\n\n" ..
			"[c " .. TextColor .. "]Cannot use with off-hand weapons"
	end,

	PlaySound = function(self)
		Audio.Play("slash" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Fury --

Skill_Fury = Base_Attack:New({

	TargetCount = Growth_Linear:New({ A = 1 / 49.0, B = 1 }),
	StaminaGain = Growth_Linear:New({ A = 50 / 49.0, B = 30 }),
	SpeedDuration = Growth_Linear:New({ A = 6 / 49.0, B = 2 }),

	GetStaminaGain = function(self, Level)
		return self.StaminaGain:Result(Level)
	end,

	GetSpeedDuration = function(self, Level)
		return self.SpeedDuration:Result(Level, RoundDown2)
	end,

	GetInfo = function(self, Source, Item)
		return
			"Strike down " .. self:GetTargetText(Source, Item) ..
			", gaining [c green]" .. self:GetStaminaGain(Item.Level) ..
			"% [c yellow]stamina[c white] and a [c green]" .. self:GetSpeedDuration(Item.Level) ..
			"[c white] second battle speed boost for a killing blow"
	end,

	PlaySound = function(self)
		Audio.Play("slash" .. Random.GetInt(0, 1) .. ".ogg")
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Target.Health + Result.Target.Health <= 0 then
			Result.Source.Stamina = self:GetStaminaGain(Level) * 0.01

			Result.Source.Buff = Buff_Hasted.Pointer
			Result.Source.BuffLevel = 30
			Result.Source.BuffDuration = self:GetSpeedDuration(Level)
			return true
		end

		return false
	end,
})

-- Gash --

Skill_Gash = Base_Attack:New({

	AttributeName = "Bleed",
	TargetCount = Growth_Linear:New({ A = 1 / 49.0, B = 1 }),
	Duration = Growth_Linear:New({ A = 0, B = Game.BleedDuration }),
	Damage = Growth_Linear:New({ A = 50 / 49.0, B = 100 }),
	Chance = Growth_Linear:New({ A = 65 / 49.0, B = 35 }),
	Bleed = Growth_Polynomial:New({ E = 3.92, A = 0.001, B = 3, C = 10 }),

	CanUse = function(self, Level, Source)
		local OffHandCount = 0
		local WeaponMain = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND1)
		if WeaponMain ~= nil and WeaponMain.Type == ITEM_OFFHAND then
			OffHandCount = OffHandCount + 1
		end

		local WeaponOff = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND2)
		if WeaponOff ~= nil and WeaponOff.Type == ITEM_OFFHAND then
			OffHandCount = OffHandCount + 1
		end

		return OffHandCount > 0
	end,

	GetDamage = function(self, Level)
		return self.Damage:Result(Level)
	end,

	GenerateDamage = function(self, Level, Source, Target)
		return math.floor(Source.GenerateDamage() * self:GetDamage(Level) * 0.01)
	end,

	GetChance = function(self, Level)
		return self.Chance:Result(Level, RoundDown2)
	end,

	GetBleedDamage = function(self, Source, Level)
		return self:GetDuration(Source, Level, true) * self:GetBleedLevel(Source, Level)
	end,

	GetBleedLevel = function(self, Source, Level)
		return self.Bleed:ModifiedResult(Level, Source.BleedPower * 0.01, 0)
	end,

	GetInfo = function(self, Source, Item)
		local TextColor = self:CanUse(Item.Level, Source, nil) and "yellow" or "red"
		local DamageValue
		if Item.MoreInfo then
			DamageValue = FormatSI(Source.GetAverageDamage() * self:GetDamage(Item.Level) * 0.01, true) .. " [c green]avg[c white]"
		else
			DamageValue = self:GetDamage(Item.Level) .. "%"
		end

		local BleedDamageValue
		if Item.MoreInfo then
			BleedDamageValue = FormatSI(self:GetBleedLevel(Source, Item.Level), true) .. "[c white] stacking bleed DPS"
		else
			BleedDamageValue = FormatSI(self:GetBleedDamage(Source, Item.Level), true) .. "[c white] stacking bleed damage over [c green]" .. self:GetDuration(Source, Item.Level, true) .. "[c white] seconds"
		end

		return
			"Slice " .. self:GetTargetText(Source, Item) .. ", dealing [c green]" .. DamageValue ..
			"[c white] weapon damage with a [c green]" .. self:GetChance(Item.Level) .. "%[c white] chance to cause [c green]" .. BleedDamageValue .. "\n\n" ..
			"[c " .. TextColor .. "]Requires at least one off-hand weapon"
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= self:GetChance(Level) then
			Result.Target.Buff = Buff_Bleeding.Pointer
			Result.Target.BuffLevel = self:GetBleedLevel(Source, Level)
			Result.Target.BuffDuration = self:GetDuration(Source, Level, true)
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("gash0.ogg")
	end,
})

-- Shield Bash --

Skill_ShieldBash = Base_Attack:New({

	TargetCount = Growth_Linear:New({ A = 1 / 49.0, B = 1 }),
	Duration = Growth_Linear:New({ A = 3 / 49.0, B = 2 }),
	Damage = Growth_Linear:New({ A = 200 / 49.0, B = 200 }),
	Chance = Growth_Diminishing:New({ A = 2051, B = 10000, C = 75 }),

	GetDamage = function(self, Level)
		return self.Damage:Result(Level)
	end,

	GetDamageMultiplier = function(self, Source, Level)
		return (self:GetDamage(Level) * 0.01) * (Source.ShieldDamage * 0.01) * (Source.AttackPower * 0.01)
	end,

	GetInfo = function(self, Source, Item)
		local TextColor = self:CanUse(Item.Level, Source, nil) and "yellow" or "red"
		local AverageDamage = 0

		local Shield = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND2)
		if Shield ~= nil then
			AverageDamage = Shield.GetAverageDamage(Source.Pointer, Shield.Upgrades)
		end

		local DamageValue
		if Item.MoreInfo then
			DamageValue = FormatSI(AverageDamage * self:GetDamageMultiplier(Source, Item.Level), true) .. " [c green]avg[c white]"
		else
			DamageValue = self:GetDamage(Item.Level) .. "%"
		end

		return
			"Bash " .. self:GetTargetText(Source, Item) .. " with a shield for [c green]" .. DamageValue ..
			"[c white] shield damage and a [c green]" .. self.Chance:Result(Item.Level) ..
			"%[c white] chance to [c yellow]stun [c white]for [c green]" .. self:GetDuration(Source, Item.Level, true) ..
			"[c white] seconds\n\n[c " .. TextColor .. "]Requires a shield"
	end,

	GenerateDamage = function(self, Level, Source, Target)
		local Shield = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND2)
		if Shield == nil then
			return 0
		end

		return math.floor(Shield.GenerateDamage(Source.Pointer, Shield.Upgrades)) * self:GetDamageMultiplier(Source, Level)
	end,

	CanUse = function(self, Level, Source)
		local Shield = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND2)
		if Shield == nil then
			return false
		end

		return Shield.Type == ITEM_SHIELD
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= self.Chance:Result(Level) then
			Result.Target.Buff = Buff_Stunned.Pointer
			Result.Target.BuffLevel = 1
			Result.Target.BuffDuration = self:GetDuration(Source, Level, true)
			return true
		end

		return false
	end,

	PlaySound = function(self)
		Audio.Play("bash" .. Random.GetInt(0, 1) .. ".ogg")
	end,
})

-- Whirlwind --

Skill_Whirlwind = Base_Attack:New({

	Damage = Growth_Linear:New({ A = 75 / 49.0, B = 75 }),

	CanUse = function(self, Level, Source)
		local Weapon = Source.GetInventoryItem(BAG_EQUIPMENT, INVENTORY_HAND1)
		if Weapon == nil then
			return false
		end

		return Weapon.Type == ITEM_TWOHANDED_WEAPON
	end,

	GetDamage = function(self, Level)
		return self.Damage:Result(Level)
	end,

	GenerateDamage = function(self, Level, Source, Target)
		return math.floor(Source.GenerateDamage() * self:GetDamage(Level) * 0.01)
	end,

	GetInfo = function(self, Source, Item)
		local TextColor = self:CanUse(Item.Level, Source, nil) and "yellow" or "red"

		local DamageValue
		if Item.MoreInfo then
			DamageValue = FormatSI(Source.GetAverageDamage() * self:GetDamage(Item.Level) * 0.01, true) .. " avg"
		else
			DamageValue = self:GetDamage(Item.Level) .. "%"
		end

		return
			"Spin around and hit all enemies for\n" ..
			"[c green]" .. DamageValue ..  "[c white] weapon damage\n\n" ..
			"[c " .. TextColor .. "]Requires a two-handed weapon"
	end,

	PlaySound = function(self)
		Audio.Play("multislash0.ogg")
	end,
})
