-- Base Power --

Base_Power = Base_Object:New({

	PowerName = "",
	PowerPerUpgrade = 1,

	GetPower = function(self, Item)
		return Item.Level + Item.Upgrades * self.PowerPerUpgrade
	end,

	GetInfo = function(self, Source, Item)
		return "Increases " .. string.lower(self.PowerName) .. " power by [c green]" .. self:GetPower(Item) .. "%"
	end,

	Stats = function(self, Item, Object, Change)
		Change[self.PowerName .. "Power"] = self:GetPower(Item)

		return Change
	end,
})

-- Base Consumable --

Base_Consume = Base_Skill:New({

	ConsumeScale = 0.25,
	DurationScale = 0.5,

	GetMultiplier = function(self, Source)
		return Source.ConsumePower * 0.01
	end,

	GetLevel = function(self, Source, Level, MoreInfo)
		local Value = Level + Level * (self.ConsumeScale * (Source.ConsumePower - 100) * 0.01)
		if MoreInfo == true then
			return Value
		else
			return math.floor(Value)
		end
	end,

	GetDuration = function(self, Source, Duration)
		return Duration + Duration * (self.DurationScale * (Source.ConsumePower - 100) * 0.01)
	end,

	GetTargetCount = function(self, Source, Level)
		return self.TargetCount:ModifiedResult(Level, 1, Source.ConsumeTargets + Source.TargetCount)
	end,
})

-- Base Throwable --

Base_Throwable = Base_Consume:New({

	IntroText = "Throw an item at",
	DurationIntroText = "over",
	DamageType = "Physical",
	ExtraDamageType = "AttackPower",
	Chance = 100,
	MinDamage = 0,
	MaxDamage = 0,
	BuffLevel = 0,
	Duration = 0,
	Pierce = 0,
	StunnedByParry = false,
	ModifierDamage = 0,
	GetDuration = Base_Consume.GetDuration,
	GetTargetCount = Base_Consume.GetTargetCount,

	GetDamageType = function(self, Source)
		return DamageTypes[self.DamageType]
	end,

	GetDuration = function(self, Source)
		local Multiplier = Source[self.AttributeName .. "Duration"] * 0.01

		return RoundDown1(self.Duration * Multiplier)
	end,

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

	GetLevelMultiplier = function(self, Source)
		local AttributeDamage = self.AttributeName and (Source[self.AttributeName .. "Power"] * 0.01) or 1.0
		local ConsumeDamage = Source.ConsumePower * 0.01

		return AttributeDamage * ConsumeDamage
	end,

	GetLevel = function(self, Source)
		return math.floor(self.BuffLevel * self:GetLevelMultiplier(Source))
	end,

	GetChance = function(self, Source, MoreInfo)
		local Value = self.Chance + self.Chance * (self.ConsumeScale * (Source.ConsumePower - 100) * 0.01)
		if MoreInfo == true then
			return Value
		else
			return math.floor(Value)
		end
	end,

	GetDamageMultiplier = function(self, Source)
		local ExtraDamage = self.ExtraDamageType and (Source[self.ExtraDamageType] * 0.01) or 1.0
		local AttributeDamage = self.DamageType and (Source[self.DamageType .. "Power"] * 0.01) or 1.0
		local ConsumeDamage = Source.ConsumePower * 0.01

		return ExtraDamage * AttributeDamage * ConsumeDamage
	end,

	GetModifierDamage = function(self, Source)
		return self.ModifierDamage
	end,

	GenerateDamage = function(self, Level, Source)
		return math.floor(Random.GetInt(self.MinDamage, self.MaxDamage) * self:GetDamageMultiplier(Source))
	end,

	GetBuffDamageText = function(self, Source, Item)
		local DPS = math.floor(self.BuffLevel * self:GetLevelMultiplier(Source))
		local Text
		if Item.MoreInfo == true then
			Text = FormatSI(DPS) .. "[c white] stacking " .. self.Buff.ShortName .. " DPS"
		else
			Text = FormatSI(math.floor(DPS * self:GetDuration(Source))) .. "[c white] stacking " .. self.Buff.ShortName .. " damage"
		end

		return "[c green]" .. Text
	end,

	GetDamageText = function(self, Source, Item)
		local Multiplier = self:GetDamageMultiplier(Source)
		local DamageText
		if Item.MoreInfo == true then
			DamageText = FormatSI((self.MinDamage + self.MaxDamage) * 0.5 * Multiplier, true) .. " [c green]avg"
		else
			local MinDamageText = FormatSI(math.floor(self.MinDamage * Multiplier))
			local MaxDamageText = FormatSI(math.floor(self.MaxDamage * Multiplier))
			DamageText = MinDamageText .. "-" .. MaxDamageText
		end
		local Text = "[c green]" .. DamageText .. "[c white] " .. string.lower(self.DamageType) .. " damage"

		return Text
	end,

	GetPierceDamageText = function(self, Source, Item)
		local Multiplier = self:GetDamageMultiplier(Source)
		local PierceDamageText = FormatSI(math.floor(self.Pierce * Multiplier))

		return "[c green]" .. PierceDamageText .. "[c white] piercing damage"
	end,

	GetDurationText = function(self, Source, Item)
		return " " .. self.DurationIntroText .. " [c green]" .. FormatDuration(self:GetDuration(Source, self.Duration))
	end,

	GetModifierText = function(self, Source)
		return ""
	end,

	GetHelpText = function(self, Source)
		return ""
	end,

	GetInfo = function(self, Source, Item)
		local TargetText = self:GetTargetText(Source, Item)
		local DamageText = (self.MinDamage > 0 and self.MaxDamage > 0) and self:GetDamageText(Source, Item) or ""
		local PierceDamageText = self.Pierce > 0 and self:GetPierceDamageText(Source, Item) or ""
		local BuffText = self:GetBuffDamageText(Source, Item) .. self:GetDurationText(Source, Item)
		local DealingText = ""
		if DamageText ~= "" and PierceDamageText ~= "" and BuffText ~= "" then
			DealingText = DamageText .. ", " .. PierceDamageText .. ", and " .. BuffText
		elseif DamageText ~= "" and PierceDamageText == "" and BuffText ~= "" then
			DealingText = DamageText .. " and " .. BuffText
		elseif DamageText == "" and PierceDamageText ~= "" and BuffText ~= "" then
			DealingText = PierceDamageText .. " and " .. BuffText
		end

		local ModifierText = self:GetModifierText(Source)
		if ModifierText ~= "" then
			ModifierText = "\n" .. ModifierText
		end

		local HelpText = self:GetHelpText(Source)
		if HelpText ~= "" then
			HelpText = "\n\n" .. HelpText
		end

		return self.IntroText .. " " .. TargetText .. ", dealing " .. DealingText .. ModifierText .. HelpText
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		local Hit = Battle_ResolveDamage(self, Level, Source, Target, Result)
		if Hit then
			self:Proc(Random.GetInt(1, 100), Level, Duration, Source, Target, Result)
		end
		Result.Source.ClearBuff = self.SourceClearBuff and self.SourceClearBuff.Pointer

		return Result
	end,

	Proc = function(self, Roll, Level, Duration, Source, Target, Result)
		if Roll <= self:GetChance(Source) then
			Result.Target.Buff = self.Buff.Pointer
			Result.Target.BuffLevel = self:GetLevel(Source, self.BuffLevel)
			Result.Target.BuffDuration = self:GetDuration(Source, self.Duration)
			Result.Target.BuffModifier = self:GetModifierDamage(Source)
			Result.Target.ClearBuff = self.TargetClearBuff and self.TargetClearBuff.Pointer
		end

		return true
	end,
})

-- Base Stunnable --

Base_Stunnable = Base_Throwable:New({

	DurationIntroText = "for",
	Buff = Buff_Stunned,
	BuffLevel = 1,
	Chance = 75,
	ConsumeScale = 0.1,
	DurationScale = 0.1,
	GetLevel = Base_Consume.GetLevel,
	GetDuration = Base_Consume.GetDuration,

	GetBuffDamageText = function(self, Source, Item)
		return "a [c green]" .. FormatSI(self:GetChance(Source, Item.MoreInfo), Item.MoreInfo) .. "%[c white] chance to stun them"
	end,

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

-- Base Bomb --

Base_Bomb = Base_Throwable:New({

	TargetCount = Growth_Linear:New({ A = 0, B = 3 }),

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

-- Base Potion --

Base_Potion = Base_Consume:New({

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

	GetBuffLevel = function(self, Source, Level)
		return math.floor(Level * self:GetMultiplier(Source))
	end,

	GetBuffDamage = function(self, Source, Level)
		return math.floor(self.Buff.UpdateCount * self:GetBuffLevel(Source, Level)) * math.floor(self:GetDuration(Source))
	end,
})

-- Base Restore --

Base_Restore = Base_Potion:New({

	GetDuration = Base_Throwable.GetDuration,
	Color = "green",

	GetMultiplier = function(self, Source)
		return (Source.ConsumePower + Source[self.AttributeName .. "Power"] - 100) * 0.01
	end,

	GetInfo = function(self, Source, Item)
		local RestoreValue
		if Item.MoreInfo == true then
			RestoreValue = FormatSI(self:GetBuffLevel(Source, Item.Level)) .. "[c white] stacking " .. self.RestoreText .. "S"
		else
			RestoreValue = FormatSI(self:GetBuffDamage(Source, Item.Level)) .. "[c white] stacking " .. self.RestoreText .. " over [c green]" .. FormatDuration(self:GetDuration(Source))
		end

		return "Restore [c " .. self.Color .. "]" .. RestoreValue
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = self.Buff.Pointer
		Result.Target.BuffLevel = self:GetBuffLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source)

		return Result
	end,
})

-- Healing Salve  --

Item_HealingSalve = Base_Restore:New({

	AttributeName = "Heal",
	RestoreText = "HP",
	Buff = Buff_Healing,
	Duration = Game.HealDuration,
})

-- Mana Cider --

Item_ManaCider = Base_Restore:New({

	AttributeName = "Mana",
	RestoreText = "MP",
	Color = "light_blue",
	Buff = Buff_Mana,
	Duration = Game.ManaDuration,
})

-- Invis Potion --

Item_InvisPotion = Base_Potion:New({

	GetInfo = function(self, Source, Item)
		return "Turn invisible and avoid battle for [c green]" .. FormatDuration(Item.Duration * self:GetMultiplier(Source)) .. "\n\n[c yellow]Effect is lost over certain terrain"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Invis.Pointer
		Result.Target.BuffLevel = Level
		Result.Target.BuffDuration = Duration * self:GetMultiplier(Source)

		return Result
	end,
})

-- Bright Potion --

Item_BrightPotion = Base_Potion:New({

	GetInfo = function(self, Source, Item)
		return "Turn the world to daylight"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Clock = Game.NoonTime - 0.05

		return Result
	end,

	CanUse = function(self, Level, Source)
		return not BloodMoonActive
	end,
})

-- Dark Potion --

Item_DarkPotion = Base_Potion:New({

	GetInfo = function(self, Source, Item)
		return "Turn the world to darkness"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Clock = 0

		return Result
	end,

	CanUse = function(self, Level, Source)
		return not BloodMoonActive
	end,
})

-- Respec Potion --

Item_RespecPotion = Base_Potion:New({

	GetInfo = function(self, Source, Item)
		return "Reset your spent skill points\n\n[c yellow]Equipped skills are set to level 1"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Respec = true

		return Result
	end,
})

-- Stash Potion --

Item_StashPotion = Base_Potion:New({

	GetInfo = function(self, Source, Item)
		return "Access your personal stash from afar"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Event = 14

		return Result
	end,
})

-- Bottle of Tears --

Item_Tears = Base_Potion:New({

	GetInfo = function(self, Source, Item)
		return "Turn the world to sadness"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Clock = Game.NoonTime - 0.05
		Result.Target.BloodMoonTime = 0

		return Result
	end,

	CanUse = function(self, Level, Source)
		return not BloodMoonActive
	end,
})

-- Potion of Regret --

Item_Regret = Base_Potion:New({

	GetInfo = function(self, Source, Item)
		return "Remove difficulty from rebirths for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration), not Item.MoreInfo)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Regretful.Pointer
		Result.Target.BuffLevel = 0
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)

		return Result
	end,
})

-- Voidstone --

Item_Voidstone = Base_Potion:New({

	GetInfo = function(self, Source, Item)
		return "Destroy all equipped cursed items"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.DestroyCursed = true

		return Result
	end,

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

-- Skill Slot --

Item_SkillSlot = {

	GetInfo = function(self, Source, Item)
		return "Increase your skill bar size"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.SkillBarSize = 1

		return Result
	end,

	CanBuy = function(self, Source, UnlockID)
		return Source.HasUnlock(UnlockID) == 0
	end,

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

-- Belt Slot --

Item_BeltSlot = {

	GetInfo = function(self, Source, Item)
		return "Increase your belt size"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.BeltSize = 1

		return Result
	end,

	CanBuy = function(self, Source, UnlockID)
		return Source.HasUnlock(UnlockID) == 0
	end,

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

-- Skill Point --

Item_SkillPoint = {

	GetInfo = function(self, Source, Item)
		local Plural = ""
		if Item.Level ~= 1 then
			Plural = "s"
		end

		return "Grants [c green]" .. Item.Level .. "[c white] extra skill point" .. Plural
	end,

	CanBuy = function(self, Source, UnlockID)
		return Source.HasUnlock(UnlockID) == 0
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.SkillPoint = Level

		return Result
	end,

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

-- Throwing Knives --

Item_ThrowingKnives = Base_Throwable:New({

	IntroText = "Throw a knife at",
	AttributeName = "Bleed",
	Buff = Buff_Bleeding,
	BuffLevel = 15,
	Duration = Game.BleedDuration,
	MinDamage = 25,
	MaxDamage = 120,
	Pierce = 50,

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

-- Poison Knives --

Item_PoisonKnives = Base_Throwable:New({

	IntroText = "Throw a poison-tipped knife at",
	AttributeName = "Poison",
	Buff = Buff_Poisoned,
	BuffLevel = 20,
	Duration = Game.PoisonDuration,
	MinDamage = 50,
	MaxDamage = 150,
	Pierce = 100,
	ModifierDamage = 50,

	GetHelpText = function(self, Source)
		return "[c yellow]Heal power is reduced when poisoned"
	end,

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

-- Firebomb --

Item_Firebomb = Base_Bomb:New({

	IntroText = "Toss an exploding potion at",
	AttributeName = "Fire",
	DamageType = "Fire",
	Buff = Buff_Burning,
	BuffLevel = 40,
	Duration = Game.FireDuration,
	MinDamage = 75,
	MaxDamage = 150,
})

-- Shrapnel Bomb --

Item_ShrapnelBomb = Base_Bomb:New({

	IntroText = "Toss an exploding contraption at",
	DurationIntroText = "for",
	Buff = Buff_Vulnerable,
	BuffLevel = 35,
	Duration = 10,
	DurationScale = 0.5,
	Pierce = 200,
	ConsumeScale = 0.25,
	GetLevel = Base_Consume.GetLevel,
	GetDuration = Base_Consume.GetDuration,

	GetBuffDamageText = function(self, Source, Item)
		return "reducing all resistances by [c green]" .. FormatSI(self:GetLevel(Source, self.BuffLevel, Item.MoreInfo)) .. "%[c white]"
	end,
})

-- Unstable Potion --

Item_UnstablePotion = Base_Bomb:New({

	IntroText = "Toss an unstable potion at",
	DurationIntroText = "for",
	DamageType = "Lightning",
	Buff = Buff_Blinded,
	BuffLevel = 30,
	Duration = 10,
	DurationScale = 0.2,
	MinDamage = 1,
	MaxDamage = 500,
	ConsumeScale = 0.25,
	GetLevel = Base_Consume.GetLevel,
	GetDuration = Base_Consume.GetDuration,

	GetBuffDamageText = function(self, Source, Item)
		return "blinding them by [c green]" .. FormatSI(self:GetLevel(Source, self.BuffLevel, Item.MoreInfo), Item.MoreInfo) .. "%[c white]"
	end,
})

-- Fire Dust --

Item_FireDust = Base_Throwable:New({

	IntroText = "Toss burning dust at",
	DurationIntroText = "for",
	DamageType = "Fire",
	Buff = Buff_Blinded,
	BuffLevel = 25,
	Duration = 10,
	DurationScale = 0.2,
	MinDamage = 25,
	MaxDamage = 75,
	ConsumeScale = 0.25,
	GetLevel = Base_Consume.GetLevel,
	GetDuration = Base_Consume.GetDuration,

	GetBuffDamageText = function(self, Source, Item)
		return "blinding them by [c green]" .. FormatSI(self:GetLevel(Source, self.BuffLevel, Item.MoreInfo), Item.MoreInfo) .. "%[c white]"
	end,

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

-- Cold Dust --

Item_ColdDust = Base_Throwable:New({

	IntroText = "Toss freezing dust at",
	DurationIntroText = "for",
	DamageType = "Cold",
	Buff = Buff_Slowed,
	BuffLevel = 40,
	Duration = 10,
	DurationScale = 0.2,
	MinDamage = 25,
	MaxDamage = 75,
	ModifierLevel = 35.25,
	ConsumeScale = 0.25,
	GetLevel = Base_Consume.GetLevel,
	GetDuration = Base_Consume.GetDuration,
	SourceClearBuff = Buff_Burning,
	TargetClearBuff = Buff_Burning,

	GetModifierDamage = function(self, Source)
		local Value = self.ModifierLevel + self.ModifierLevel * (1 * (Source.ConsumePower - 100) * 0.01)

		return math.floor(Value)
	end,

	GetModifierText = function(self, Source)
		return "Slowed enemies take [c green]" .. self:GetModifierDamage(Source) .. "%[c white] more damage from ice imps"
	end,

	GetHelpText = function(self, Source)
		return "Purges [c yellow]burning"
	end,

	GetBuffDamageText = function(self, Source, Item)
		return "slowing them by [c green]" .. FormatSI(self:GetLevel(Source, self.BuffLevel, Item.MoreInfo), Item.MoreInfo) .. "%[c white]"
	end,

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

-- Lava Sludge --

Item_LavaSludge = Base_Throwable:New({

	IntroText = "Toss a handful of lava at",
	AttributeName = "Fire",
	DamageType = "Fire",
	Buff = Buff_Burning,
	BuffLevel = 60,
	Duration = Game.FireDuration,
	MinDamage = 100,
	MaxDamage = 200,
	SourceClearBuff = Buff_Flayed,
	TargetClearBuff = Buff_Flayed,

	GetHelpText = function(self, Source)
		return "Purges [c yellow]flayed"
	end,

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

-- Poison Potion --

Item_PoisonPotion = Base_Throwable:New({

	IntroText = "Throw a jar of poison at",
	AttributeName = "Poison",
	Buff = Buff_Poisoned,
	BuffLevel = 10,
	Duration = Game.PoisonDuration,
	Pierce = 25,
	ModifierDamage = 35,
	TargetCount = Growth_Linear:New({ A = 0, B = 3 }),

	GetHelpText = function(self, Source)
		return "[c yellow]Heal power is reduced when poisoned"
	end,

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

-- Death Potion --

Item_DeathPotion = Base_Throwable:New({

	IntroText = "Throw a jar of death at",
	AttributeName = "Bleed",
	Buff = Buff_Bleeding,
	BuffLevel = 1000,
	Duration = Game.BleedDuration,
	Pierce = 1000,
	TargetCount = Growth_Linear:New({ A = 0, B = 3 }),

	GetHelpText = function(self, Source)
		return "[c blood]Do not drink"
	end,

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

-- Bone --

Item_Bone = Base_Stunnable:New({

	IntroText = "Throw a large bone at",
	DamageType = "Physical",
	Chance = 70,
	Duration = 3,
	MinDamage = 50,
	MaxDamage = 200,
})

-- Snowball --

Item_Snowball = Base_Stunnable:New({

	IntroText = "Throw a snowball at",
	DamageType = "Cold",
	Chance = 75,
	Duration = 2,
	MinDamage = 100,
	MaxDamage = 250,
})

-- Slimy Glob --

Item_SlimyGlob = Base_Consume:New({

	GetInfo = function(self, Source, Item)
		local DurationText = FormatDuration(self:GetDuration(Source, Item.Duration))
		local ValueText = FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo), Item.MoreInfo)
		return
			"If bleeding, gain [c green]" .. ValueText .. "% [c yellow]bleed [c white]resist for [c green]" .. DurationText .. " [c white]\n" ..
			"Purges [c yellow]bleeding"
	end,

	CanTarget = function(self, Source, Target, First)
		return Target.HasBuff(Buff_Bleeding.Pointer)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		if Target.HasBuff(Buff_Bleeding.Pointer) then
			Result.Target.Buff = Buff_BleedResist.Pointer
			Result.Target.BuffLevel = self:GetLevel(Source, Level)
			Result.Target.BuffDuration = self:GetDuration(Source, Duration)
			Result.Target.ClearBuff = Buff_Bleeding.Pointer
		end

		return Result
	end,

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

-- Crab Legs --

Item_CrabLegs = Base_Consume:New({

	ConsumeScale = 0.75,
	DurationScale = 0.25,

	GetInfo = function(self, Source, Item)
		return "Gain [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo), Item.MoreInfo) .. " [c white]armor for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration)) .. " [c white]\n\nPurges [c yellow]fractured"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Hardened.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.ClearBuff = Buff_Fractured.Pointer

		return Result
	end,

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

-- Crow Feather --

Item_CrowFeather = Base_Consume:New({

	GetInfo = function(self, Source, Item)
		return "Increase move speed by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo), Item.MoreInfo) .. "% [c white]for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration)) .. " [c white]\n\nPurges [c yellow]slowness"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Fast.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.ClearBuff = Buff_Slowed.Pointer

		return Result
	end,

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

-- Spider Leg --

Item_SpiderLeg = Base_Consume:New({

	GetInfo = function(self, Source, Item)
		return "If slowed, increase battle speed by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo), Item.MoreInfo) .. "% [c white]for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration)) .. "[c white]\n\nPurges [c yellow]slowness"
	end,

	CanTarget = function(self, Source, Target, First)
		return Target.HasBuff(Buff_Slowed.Pointer)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		if Target.HasBuff(Buff_Slowed.Pointer) then
			Result.Target.Buff = Buff_Hasted.Pointer
			Result.Target.BuffLevel = self:GetLevel(Source, Level)
			Result.Target.BuffDuration = self:GetDuration(Source, Duration)
			Result.Target.ClearBuff = Buff_Slowed.Pointer
		end

		return Result
	end,

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

-- Fang --

Item_Fang = Base_Consume:New({

	GetInfo = function(self, Source, Item)
		return "If poisoned, gain [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo), Item.MoreInfo) .. "% [c yellow]poison [c white]resist for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration)) .. "[c white]\n\nPurges [c yellow]poisoned"
	end,

	CanTarget = function(self, Source, Target, First)
		return Target.HasBuff(Buff_Poisoned.Pointer)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		if Target.HasBuff(Buff_Poisoned.Pointer) then
			Result.Target.Buff = Buff_PoisonResist.Pointer
			Result.Target.BuffLevel = self:GetLevel(Source, Level)
			Result.Target.BuffDuration = self:GetDuration(Source, Duration)
			Result.Target.ClearBuff = Buff_Poisoned.Pointer
		end

		return Result
	end,

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

-- Spectral Dust --

Item_SpectralDust = Base_Consume:New({

	ConsumeScale = 0.5,

	GetInfo = function(self, Source, Item)
		return "Increase cold resist by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo), Item.MoreInfo) .. "%[c white] for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration))
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_ColdResist.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)

		return Result
	end,

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

-- Teleport Scroll --

Item_TeleportScroll = {

	GetInfo = function(self, Source, Item)
		local MapName = Source.SpawnName()
		if MapName == nil then
			MapName = "Home"
		end

		return "Teleport to [c green]" .. MapName .. "[c white] after [c green]" .. FormatDuration(Item.Duration)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Teleport = Duration

		return Result
	end,
}

-- Ankh --

Item_Ankh = Base_Consume:New({

	GetMultiplier = function(self, Source)
		return (Source.ConsumePower * 0.01) * (Source.HealPower * 0.01)
	end,

	GetHeal = function(self, Source, Level)
		return math.floor(Level * self:GetMultiplier(Source))
	end,

	GetInfo = function(self, Source, Item)
		local TargetText = self:GetTargetText(Source, Item)

		return "Resurrect " .. TargetText .. " with [c green]" .. FormatSI(self:GetHeal(Source, Item.Level)) .. "[c white] HP\n\n[c yellow]Can be used outside of battle"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Health = self:GetHeal(Source, Level)
		Result.Target.Corpse = 1

		return Result
	end,

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

-- Swamp Glob --

Item_SwampGlob = Base_Consume:New({
	DurationScale = 0.2,

	GetInfo = function(self, Source, Item)
		local TargetText = self:GetTargetText(Source, Item)

		return "Slow " .. TargetText .. " by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo), Item.MoreInfo) .. "% [c white]for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration)) .. "[c white]\n\nPurges [c yellow]burning"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Slowed.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.BuffModifier = 0
		Result.Target.ClearBuff = Buff_Burning.Pointer
		Result.Source.ClearBuff = Buff_Burning.Pointer

		return Result
	end,

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

-- Stinger --

Item_Stinger = Base_Consume:New({

	ConsumeScale = 0.75,
	DurationScale = 0.25,

	GetInfo = function(self, Source, Item)
		return "Increase attack power by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo)) .. "%[c white] for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration)) .. "[c white]\n\nPurges [c yellow]weakness"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Empowered.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.ClearBuff = Buff_Weak.Pointer

		return Result
	end,

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

-- Elusive Potion --

Item_ElusivePotion = Base_Consume:New({

	TargetCount = Growth_Linear:New({ A = 0, B = 3 }),
	ConsumeScale = 0.4,

	GetInfo = function(self, Source, Item)
		local TargetText = self:GetTargetText(Source, Item)

		return "Throw down smoke cover for " .. TargetText ..", increasing evasion by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo)) .. "%[c white] for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration))
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Evasion.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)

		return Result
	end,

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

-- Haste Potion --

Item_HastePotion = Base_Consume:New({

	TargetCount = Growth_Linear:New({ A = 0, B = 3 }),
	ConsumeScale = 0.4,

	GetInfo = function(self, Source, Item)
		local TargetText = self:GetTargetText(Source, Item)

		return
			"Energize " .. TargetText ..", increasing battle speed by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo)) .. "%[c white] " ..
			"for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration)) .. "\n\n" ..
			"Purges [c yellow]stunned"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Hasted.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.ClearBuff = Buff_Stunned.Pointer

		return Result
	end,

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

-- Battle Potion --

Item_BattlePotion = Base_Potion:New({

	ConsumeScale = 1,
	DurationScale = 0,

	GetInfo = function(self, Source, Item)
		return "Get into a fight"
	end,

	CanUse = function(self, Level, Source)
		return Source.GetTileZone(Source.X, Source.Y) > 0
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Difficult.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.Battle = Source.GetTileZone(Source.X, Source.Y)

		return Result
	end,
})

-- Greater Battle Potion --

Item_GreaterBattlePotion = Base_Potion:New({

	ConsumeScale = 0.5,
	DurationScale = 0.25,

	GetInfo = function(self, Source, Item)
		return "Increase difficulty by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo)) .. "%[c white] for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration), not Item.MoreInfo)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Difficult.Pointer
		Result.Target.BuffLevel = self:GetLevel(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)

		return Result
	end,
})

-- Ultimate Battle Potion --

Item_UltimateBattlePotion = Base_Potion:New({

	Difficulty = 200,
	DifficultyScale = 0.5,
	ConsumeScale = 0.2,
	DurationScale = 0.25,

	GetDifficulty = function(self, Source, Level, MoreInfo)
		local Value = self.Difficulty + self.Difficulty * (self.DifficultyScale * (Source.ConsumePower - 100) * 0.01)
		if MoreInfo == true then
			return Value
		else
			return math.floor(Value)
		end
	end,

	GetInfo = function(self, Source, Item)
		return "Reduce current boss cooldowns by [c green]" .. FormatSI(self:GetLevel(Source, Item.Level, Item.MoreInfo)) .. "%[c white]\nIncrease difficulty by [c green]" .. FormatSI(self:GetDifficulty(Source, Item.Level, Item.MoreInfo)) .. "%[c white] for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration), not Item.MoreInfo)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Difficult.Pointer
		Result.Target.BuffLevel = self:GetDifficulty(Source, Level)
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.CurrentBossCooldowns = self:GetLevel(Source, Level)

		return Result
	end,
})

-- Belligerent Potion --

Item_BelligerentPotion = Base_Potion:New({

	DurationScale = 0.5,

	GetInfo = function(self, Source, Item)
		return "Get into fights more often for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration))
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Attractant.Pointer
		Result.Target.BuffLevel = 2
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.Battle = Source.GetTileZone(Source.X, Source.Y)
		Target.SetNextBattle(0)

		return Result
	end,
})

-- Lava Potion --

Item_LavaPotion = Base_Potion:New({

	DurationScale = 1,

	GetInfo = function(self, Source, Item)
		return "Grants lava immunity for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration), not Item.MoreInfo)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_LavaImmune.Pointer
		Result.Target.BuffLevel = 0
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)

		return Result
	end,
})

-- Warming Torch --

Item_WarmingTorch = Base_Consume:New({

	DurationScale = 1,

	GetInfo = function(self, Source, Item)
		return "Grants freeze immunity for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration), not Item.MoreInfo)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Warm.Pointer
		Result.Target.BuffLevel = 0
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)
		Result.Target.ClearBuff = Buff_Freezing.Pointer

		return Result
	end,

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

-- Cloudy Potion --

Item_CloudyPotion = Base_Potion:New({

	DurationScale = 1,

	GetInfo = function(self, Source, Item)
		return "Grants fall damage immunity for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration), not Item.MoreInfo)
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_FallImmune.Pointer
		Result.Target.BuffLevel = 0
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)

		return Result
	end,
})

-- Torch --

Item_Torch = {

	GetDuration = function(self, Source, Duration)
		return math.floor(Duration * (Source.ConsumePower * 0.01))
	end,

	GetInfo = function(self, Source, Item)
		return "Give light for [c green]" .. FormatDuration(self:GetDuration(Source, Item.Duration), not Item.MoreInfo) .. " [c white]"
	end,

	Use = function(self, Level, Duration, Source, Target, Result, Priority)
		Result.Target.Buff = Buff_Light.Pointer
		Result.Target.BuffLevel = Level
		Result.Target.BuffDuration = self:GetDuration(Source, Duration)

		return Result
	end,

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

-- Flippers --

Item_Flippers = {

	GetInfo = function(self, Source, Item)
		return "[c yellow]Grants movement over shallow water"
	end,

	Stats = function(self, Item, Object, Change)
		Change.Flippers = true

		return Change
	end,
}

-- Mountain --

Item_Mountain = {

	GetInfo = function(self, Source, Item)
		return "[c yellow]Grants movement over rugged terrain"
	end,

	Stats = function(self, Item, Object, Change)
		Change.Mountain = true

		return Change
	end,
}

-- FallResist --

Item_FallResist = {

	GetInfo = function(self, Source, Item)
		local Damage = Script_Fall:GetLevel(Source) * Script_Fall.HealthMultiplier

		return
			"[c yellow]Reduce fall damage by [c green]" .. self:GetBonus(Source, Item) .. "%\n\n" ..
			"Current fall damage is [c red]" .. FormatSI(Damage)
	end,

	GetBonus = function(self, Source, Item)
		return Item.Level + Item.Upgrades * Items[Item.ID].Increase
	end,

	Stats = function(self, Item, Object, Change)
		Change.FallResist = self:GetBonus(Object, Item)

		return Change
	end,
}

-- Diagonal --

Item_Diagonal = {

	GetInfo = function(self, Source, Item)
		return "[c yellow]Grants diagonal movement"
	end,

	Stats = function(self, Item, Object, Change)
		Change.DiagonalMovement = true

		return Change
	end,
}

-- Lava Protection --

Item_LavaProtection = {

	GetInfo = function(self, Source, Item)
		return "[c yellow]Grants lava immunity"
	end,

	Stats = function(self, Item, Object, Change)
		Change.LavaProtection = true

		return Change
	end,
}

-- Freeze Protection --

Item_FreezeProtection = {

	GetInfo = function(self, Source, Item)
		return "[c yellow]Grants freeze immunity"
	end,

	Stats = function(self, Item, Object, Change)
		Change.FreezeProtection = true

		return Change
	end,
}

-- Gold Gained --

Item_GoldGained = {

	GetGained = function(self, Source, Item)
		return Item.Level + Item.Upgrades * Items[Item.ID].Increase
	end,

	GetInfo = function(self, Source, Item)
		return "Increase gold gained by [c green]" .. self:GetGained(Source, Item) .. "%"
	end,

	Stats = function(self, Item, Object, Change)
		Change.GoldGained = self:GetGained(Object, Item)

		return Change
	end,
}

-- Experience Gained --

Item_ExperienceGained = {

	GetGained = function(self, Source, Item)
		return Item.Level + Item.Upgrades * Items[Item.ID].Increase
	end,

	GetInfo = function(self, Source, Item)
		return "Increase experience gained by [c green]" .. self:GetGained(Source, Item) .. "%"
	end,

	Stats = function(self, Item, Object, Change)
		Change.ExperienceGained = self:GetGained(Object, Item)

		return Change
	end,
}

-- Set Limit --

Item_SetLimit = {

	GetInfo = function(self, Source, Item)
		return "Reduce set requirements by [c green]" .. Item.Level
	end,

	Stats = function(self, Item, Object, Change)
		Change.SetLimit = -Item.Level

		return Change
	end,
}

-- Target Count --

Item_TargetCount = {

	GetInfo = function(self, Source, Item)
		return "Increase target count by [c green]" .. Item.Level
	end,

	Stats = function(self, Item, Object, Change)
		Change.TargetCount = Item.Level

		return Change
	end,
}

-- Pain Ring --

Item_PainRing = {

	GetDifficulty = function(self, Source, Item)
		return math.floor(Item.Level + Item.Upgrades * Items[Item.ID].Increase)
	end,

	GetInfo = function(self, Source, Item)
		return "Increase difficulty by [c green]" .. self:GetDifficulty(Source, Item) .. "%"
	end,

	Stats = function(self, Item, Object, Change)
		Change.Difficulty = self:GetDifficulty(Source, Item)

		return Change
	end,
}

-- Lucky Amulet --

Item_LuckyAmulet = {

	GetInfo = function(self, Source, Item)
		return "[c yellow]Increases gambling speed"
	end,

	Stats = function(self, Item, Object, Change)
		Change.MinigameSpeed = 2

		return Change
	end,
}

-- Mana Shield--

Item_ManaShield = {

	ReductionPerUpgrade = 1,

	GetReduction = function(self, Item)
		return Item.Level + Item.Upgrades * self.ReductionPerUpgrade
	end,

	GetInfo = function(self, Source, Item)
		return "Convert [c green]" .. self:GetReduction(Item) .. "%[c white] of attack damage taken to mana drain"
	end,

	Stats = function(self, Item, Object, Change)
		Change.ManaShield = self:GetReduction(Item)

		return Change
	end,
}

-- Drop Rate --

Item_DropRate = {

	ChancePerUpgrade = 4,

	GetInfo = function(self, Source, Item)
		return "Increase item drop rate from monsters by [c green]" .. self:GetChance(Item) .. "%[c white]"
	end,

	GetChance = function(self, Item)
		return Item.Level + Item.Upgrades * self.ChancePerUpgrade
	end,

	Stats = function(self, Item, Object, Change)
		Change.DropRate = self:GetChance(Item)

		return Change
	end,
}

-- Constricting Amulet --

Item_ConstrictingAmulet = {

	LevelPerUpgrade = 3.75,

	GetInfo = function(self, Source, Item)
		return "Increase monster count in battle by [c green]" .. self:GetAmount(Item) .. "%[c white]"
	end,

	GetAmount = function(self, Item)
		return math.floor(Item.Level + Item.Upgrades * self.LevelPerUpgrade)
	end,

	Stats = function(self, Item, Object, Change)
		Change.MonsterCount = self:GetAmount(Item)

		return Change
	end,
}

-- Hangman's Noose --

Item_Noose = {

	DifficultyMultiplier = Growth_Linear:New({ A = 1.3 / 20.0, B = 0.2 }),

	GetInfo = function(self, Source, Item)
		return "Increase difficulty multiplier by [c green]" .. self:GetAmount(Item)
	end,

	GetAmount = function(self, Item)
		return self.DifficultyMultiplier:Result(Item.Upgrades + 1, RoundDown2)
	end,

	Stats = function(self, Item, Object, Change)
		Change.DifficultyMultiplier = self:GetAmount(Item)

		return Change
	end,
}

-- Dark Note --

Item_DarkNote = {

	GetInfo = function(self, Source, Item)
		return "[c gray]Great power lies within the tower..."
	end,
}

-- End Note --

Item_EndNote = {

	GetInfo = function(self, Source, Item)
		return "[c gray]Chores aren't finished yet."
	end,
}

-- Final Note --

Item_FinalNote = {

	GetInfo = function(self, Source, Item)
		return "[c gray]Chores are finally done?"
	end,
}

-- Ultimate Note --

Item_UltimateNote = {

	GetInfo = function(self, Source, Item)
		return "[c gray]Chores are finally done... hooray."
	end,
}

-- Credits --

Item_Credits = {

	GetInfo = function(self, Source, Item)
		return "Thank you for playing!\n\n[c gray]Programming\nAlan Witkowski\n\n[c gray]Game Design\nAlan Witkowski\n\n[c gray]Artwork\nAlan Witkowski\n\n[c gray]Sound Design\nAlan Witkowski\n\n[c gray]Music\nAlan Witkowski"
	end,
}

-- Dark Ring --

Item_DarkRing = Base_Set:New({

	PowerPerUpgrade = 1,

	GetPower = function(self, Item)
		return Item.Level + Item.Upgrades * self.PowerPerUpgrade
	end,

	GetInfo = function(self, Source, Item)
		return "Increases summon power by [c green]" .. self:GetPower(Item) .. "%"
	end,

	Stats = function(self, Item, Object, Change)
		Change.SummonPower = self:GetPower(Item)

		return Change
	end,
})

-- Attack Power --

Item_AttackPower = Base_Power:New({

	PowerName = "Attack",
})

-- Mundane Amulet  --

SetBonus_MundaneAmulet = Base_Set:New({

	ChancePerUpgrade = 2,

	Attributes = {
		HitChance = { "5%", "25%" }
	},

	GetInfo = function(self, Source, Item)
		return "Decrease chance to consume items in battle by [c green]" .. self:GetChance(Item) .. "%[c white]\n\n" .. self:GetAddedInfo(Source, Item)
	end,

	GetChance = function(self, Item)
		return Item.Level + Item.Upgrades * self.ChancePerUpgrade
	end,

	Stats = function(self, Item, Object, Change)
		Change.ConsumeChance = -self:GetChance(Item)

		return Change
	end,
})
