-- Base Buff --

Base_Buff = Base_Object:New({

	UpdateCount = 1,
	AttributeName = "",

	GetInfo = function(self, Effect)
		return ""
	end,

	GetChange = function(self, Level)
		return math.floor(self.UpdateCount * Level)
	end,

	UpdateHealth = function(self, Level, Source, Change)
		Change.Health = -math.floor(Level * Source.GetDamageReduction(self.DamageType))

		return Change
	end,

	Update = function(self, Level, Source, Change)
		Change[self.AttributeName] = self:GetChange(Level)

		return Change
	end,

	Stats = function(self, Level, Source, Change)
		Change[self.AttributeName] = self:GetChange(Level)

		return Change
	end,
})

-- Healing --

Buff_Healing = Base_Buff:New({

	AttributeName = "Health",
	Stats = false,

	GetInfo = function(self, Effect)
		return "Slowly healing for [c green]" .. FormatSI(self:GetChange(Effect.Level)) .. " [c white]HP"
	end,
})

-- Mana --

Buff_Mana = Base_Buff:New({

	AttributeName = "Mana",
	Stats = false,

	GetInfo = function(self, Effect)
		return "Slowly regaining [c light_blue]" .. FormatSI(self:GetChange(Effect.Level)) .. " [c white]MP"
	end,
})

-- Bleeding --

Buff_Bleeding = Base_Buff:New({

	ShortName = "bleed",
	DamageType = DamageTypes["Bleed"],
	Update = Base_Buff.UpdateHealth,
	Stats = false,

	GetInfo = function(self, Effect)
		return "Slowly bleeding for [c red]" .. FormatSI(self:GetChange(Effect.Level)) .. " [c white]damage"
	end,
})

-- Poisoned --

Buff_Poisoned = Base_Buff:New({

	ShortName = "poison",
	HealthUpdateMultiplier = -50,
	DamageType = DamageTypes["Poison"],
	Update = Base_Buff.UpdateHealth,

	GetInfo = function(self, Effect)
		return
			"Heal power reduced by [c red]" .. math.abs(self.HealthUpdateMultiplier) .. "%\n" ..
			"Taking [c green]" .. Effect.Modifier .. "%[c white] more damage from skeletons\n" ..
			"Taking [c red]" .. FormatSI(self:GetChange(Effect.Level)) .. " [c white]damage"
	end,

	Stats = function(self, Level, Source, Change)
		Change.HealthUpdateMultiplier = self.HealthUpdateMultiplier

		return Change
	end,
})

-- Burning --

Buff_Burning = Base_Buff:New({

	ShortName = "fire",
	DamageType = DamageTypes["Fire"],
	Update = Base_Buff.UpdateHealth,
	Stats = false,

	GetDemonDamage = function(self, Stacks)
		return 3.574 * Stacks / (135.3 + Stacks) + 0.005
	end,

	GetInfo = function(self, Effect)
		return
			"Burning for [c red]" .. FormatSI(self:GetChange(Effect.Level)) .. " [c white]damage\n" ..
			"Taking [c green]" .. math.floor(self:GetDemonDamage(Effect.Stacks) * 100) .. "%[c white] more damage from demons\n"
	end,
})

-- Freezing --

Buff_Freezing = Base_Buff:New({

	DamageType = DamageTypes["Cold"],
	SlowLevel = 200,
	Update = Base_Buff.UpdateHealth,

	GetInfo = function(self, Effect)
		return "Freezing for [c red]" .. FormatSI(self:GetChange(Effect.Level)) .. " [c white]damage\nSpeed reduced by [c green]" .. self.SlowLevel .. "%"
	end,

	Stats = function(self, Level, Source, Change)
		Change.BattleSpeed = -self.SlowLevel
		Change.MoveSpeed = -self.SlowLevel

		return Change
	end,
})

-- Invis --

Buff_Invis = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return "Avoiding battle"
	end,

	Stats = function(self, Level, Source, Change)
		Change.Invisible = true

		return Change
	end,
})

-- Slowed --

Buff_Slowed = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		local IceImpText = Effect.Modifier > 0 and "Taking [c green]" .. Effect.Modifier .. "%[c white] more damage from ice imps\n" or ""

		return "Speed reduced by [c green]" .. self:GetChange(Effect.Level) .. "%\n" .. IceImpText
	end,

	Stats = function(self, Level, Source, Change)
		Change.BattleSpeed = -self:GetChange(Level)
		Change.MoveSpeed = -self:GetChange(Level) * 2

		return Change
	end,
})

-- Stunned --

Buff_Stunned = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return "Unable to act"
	end,

	Stats = function(self, Level, Source, Change)
		Change.Stunned = true

		return Change
	end,
})

-- Taunted --

Buff_Taunted = Base_Buff:New({

	AttributeName = "NegativeEvasion",
	Update = false,

	GetInfo = function(self, Effect)
		return
			"Can only target taunter\n" ..
			"Evasion reduced by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Hasted --

Buff_Hasted = Base_Buff:New({

	AttributeName = "BattleSpeed",
	Update = false,

	GetInfo = function(self, Effect)
		return "Battle speed increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Fast --

Buff_Fast = Base_Buff:New({

	AttributeName = "MoveSpeed",
	Update = false,

	GetInfo = function(self, Effect)
		return "Move speed increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Blinded --

Buff_Blinded = Base_Buff:New({

	AttributeName = "HitChance",
	UpdateCount = -1,
	Update = false,

	GetInfo = function(self, Effect)
		return "Hit chance reduced by [c green]" .. math.abs(self:GetChange(Effect.Level)) .. "%"
	end,
})

-- Mighty --

Buff_Mighty = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return "Weapon damage increased by [c green]" .. self:GetChange(Effect.Level)
	end,

	Stats = function(self, Level, Source, Change)
		Change.MinDamage = self:GetChange(Level)
		Change.MaxDamage = self:GetChange(Level)

		return Change
	end,
})

-- Hardened --

Buff_Hardened = Base_Buff:New({

	AttributeName = "Armor",
	Update = false,

	GetInfo = function(self, Effect)
		return "Armor increased by [c green]" .. self:GetChange(Effect.Level)
	end,
})

-- Evasion --

Buff_Evasion = Base_Buff:New({

	AttributeName = "Evasion",
	Update = false,

	GetInfo = function(self, Effect)
		return "Evasion increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Parry --

Buff_Parry = Base_Buff:New({

	StaminaGain = 0.2,
	StunDuration = 1,
	Update = false,
	Stats = false,

	GetInfo = function(self, Effect)
		return "Blocking [c green]" .. self:GetChange(Effect.Level) .. "%[c white] damage from attacks"
	end,

	OnHit = function(self, Action, Object, Effect, Change, Result)
		Change.BuffSound = self.ID
		Change.Damage = math.max(math.floor(Change.Damage * (1.0 - (Effect.Level / 100.0))), 0)
		Change.Stamina = self.StaminaGain

		-- Stun target
		if Action.StunnedByParry ~= false then
			Result.Source.Buff = Buff_Stunned.Pointer
			Result.Source.BuffLevel = 1
			Result.Source.BuffDuration = self.StunDuration
		end
	end,

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

-- Dodge --

Buff_Dodge = Base_Buff:New({

	AttributeName = "Evasion",
	StaminaGain = 0.3,
	Update = false,

	GetInfo = function(self, Effect)
		return "Dodging attacks"
	end,

	OnMiss = function(self, Object, Effect, Change, Result)
		Change.BuffSound = self.ID
		Change.Stamina = self.StaminaGain
	end,
})

-- Bleed Resist --

Buff_BleedResist = Base_Buff:New({

	AttributeName = "BleedResist",
	Update = false,

	GetInfo = function(self, Effect)
		return "Bleed resist increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Poison Resist --

Buff_PoisonResist = Base_Buff:New({

	AttributeName = "PoisonResist",
	Update = false,

	GetInfo = function(self, Effect)
		return "Poison resist increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Cold Resist --

Buff_ColdResist = Base_Buff:New({

	AttributeName = "ColdResist",
	Update = false,

	GetInfo = function(self, Effect)
		return "Cold resist increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Weak --

Buff_Weak = Base_Buff:New({

	AttributeName = "AttackPower",
	UpdateCount = -1,
	Update = false,

	GetInfo = function(self, Effect)
		return "Attack damage reduced by [c green]" .. math.abs(self:GetChange(Effect.Level)) .. "%"
	end,
})

-- Vulnerable --

Buff_Vulnerable = Base_Buff:New({

	AttributeName = "AllResist",
	Update = false,
	UpdateCount = -1,

	GetInfo = function(self, Effect)
		return "All resistances reduced by [c green]" .. math.abs(self:GetChange(Effect.Level)) .. "%"
	end,
})

-- Flayed --

Buff_Flayed = Base_Buff:New({

	AttributeName = "ElementalResist",
	UpdateCount = -1,
	Update = false,

	GetInfo = function(self, Effect)
		return "Elemental resist reduced by [c green]" .. math.abs(self:GetChange(Effect.Level)) .. "%"
	end,
})

-- Fractured --

Buff_Fractured = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return
			"Physical resist reduced by [c green]" .. self:GetChange(Effect.Level) .. "%\n" ..
			"Poison resist reduced by [c green]" .. self:GetChange(Effect.Level) .. "%\n" ..
			"Bleed resist reduced by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,

	Stats = function(self, Level, Source, Change)
		Change.PhysicalResist = -Level
		Change.PoisonResist = -Level
		Change.BleedResist = -Level

		return Change
	end,
})

-- Light --

Buff_Light = Base_Buff:New({

	AttributeName = "Light",
	Update = false,

	GetInfo = function(self, Effect)
		return "Giving off light"
	end,
})

-- Shielded --

Buff_Shielded = Base_Buff:New({

	Update = false,
	Stats = false,

	GetInfo = function(self, Effect)
		return "Blocking [c green]" .. FormatSI(Effect.Level) .. "[c white] attack damage"
	end,

	OnHit = function(self, Action, Object, Effect, Change, Result)

		-- Check for incoming damage
		if Change.Damage > 0 then
			Change.BuffSound = self.ID
		end

		-- Reduce shield
		Level = Effect.Level - Change.Damage

		-- Check for shield breaking
		if Level <= 0 then
			Change.Damage = math.abs(Level)
			Object.ClearBuff(self.ID)
		else
			Change.Damage = 0
			Object.UpdateBuff(self.ID, Level)
		end
	end,

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

-- Empowered --

Buff_Empowered = Base_Buff:New({

	AttributeName = "AttackPower",
	Update = false,

	GetInfo = function(self, Effect)
		return "Attack damage increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Sanctuary --

Buff_Sanctuary = Base_Buff:New({

	Heal = 2.5,
	Armor = 1,
	DamageBlock = 2,

	GetInfo = function(self, Effect)
		return
			"Armor increased by [c green]" .. FormatSI(self.Armor * Effect.Level) .. "[c white]\n" ..
			"Damage block increased by [c green]" .. FormatSI(self.DamageBlock * Effect.Level) .. "[c white]\n" ..
			"Slowly healing for [c green]" .. FormatSI(math.floor(self.Heal * Effect.Level)) .. " [c white]HP"
	end,

	Stats = function(self, Level, Source, Change)
		Change.Armor = self.Armor * Level
		Change.DamageBlock = self.DamageBlock * Level

		return Change
	end,

	Update = function(self, Level, Source, Change)
		Change.Health = math.floor(self.Heal * Level)

		return Change
	end,
})

-- Spring Water --

Buff_Spring = Base_Buff:New({

	Stats = false,

	GetInfo = function(self, Effect)
		return
			"Slowly healing for [c green]" .. FormatSI(math.floor(Effect.Level)) .. " [c white]HP\n" ..
			"Slowly regaining [c light_blue]" .. FormatSI(math.floor(Effect.Level)) .. "[c white] MP"
	end,

	Update = function(self, Level, Source, Change)
		Change.Health = math.floor(Level)
		Change.Mana = math.floor(Level)

		return Change
	end,
})

-- Demons --

Buff_SummonDemon = Base_Buff:New({

	Stats = false,
	Update = false,

	GetInfo = function(self, Effect)
		Plural = ""
		if Level ~= 1 then
			Plural = "s"
		end

		return "Carrying [c green]" .. self:GetChange(Effect.Level) .. "[c white] demon" .. Plural
	end,

	GetSummonSkill = function(self)
		return Skill_DemonicConjuring.Item.Pointer
	end,
})

-- Ice Imp --

Buff_SummonIceImp = Base_Buff:New({

	Stats = false,
	Update = false,

	GetInfo = function(self, Effect)
		Plural = ""
		if Level ~= 1 then
			Plural = "s"
		end

		return "Carrying [c green]" .. self:GetChange(Effect.Level) .. "[c white] ice imp" .. Plural
	end,

	GetSummonSkill = function(self)
		return Skill_DemonicConjuring.Item.Pointer
	end,
})

-- Skeletons --

Buff_SummonSkeleton = Base_Buff:New({

	Stats = false,
	Update = false,

	GetInfo = function(self, Effect)
		Plural = ""
		if Level ~= 1 then
			Plural = "s"
		end

		return "Carrying [c green]" .. self:GetChange(Effect.Level) .. "[c white] skeleton" .. Plural
	end,

	GetSummonSkill = function(self)
		return Skill_RaiseDead.Item.Pointer
	end,
})

-- Skeleton Priests --

Buff_SummonSkeletonPriest = Base_Buff:New({

	Stats = false,
	Update = false,

	GetInfo = function(self, Effect)
		Plural = ""
		if Level ~= 1 then
			Plural = "s"
		end

		return "Carrying [c green]" .. self:GetChange(Effect.Level) .. "[c white] skeleton priest" .. Plural
	end,

	GetSummonSkill = function(self)
		return Skill_RaiseDead.Item.Pointer
	end,
})

-- Difficult --

Buff_Difficult = Base_Buff:New({

	AttributeName = "Difficulty",
	Update = false,

	GetInfo = function(self, Effect)
		return "Difficulty increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Attractant --

Buff_Attractant = Base_Buff:New({

	AttributeName = "Attractant",
	Update = false,

	GetInfo = function(self, Effect)
		return "Getting into battle more often"
	end,
})

-- Lava Immune --

Buff_LavaImmune = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return "Immune to lava"
	end,

	Stats = function(self, Level, Source, Change)
		Change.LavaProtection = true

		return Change
	end,
})

-- Fall Immune --

Buff_FallImmune = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return "Immune to fall damage"
	end,

	Stats = function(self, Level, Source, Change)
		Change.FallResist = 100

		return Change
	end,
})

-- Warm --

Buff_Warm = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return "Immune to freezing"
	end,

	Stats = function(self, Level, Source, Change)
		Change.FreezeProtection = true

		if Source.Light == 0 then
			Change.Light = 31
		end

		return Change
	end,
})

-- Regretful --

Buff_Regretful = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return "Removing all difficulty from rebirths"
	end,

	Stats = function(self, Level, Source, Change)
		Change.Regretful = true

		return Change
	end,
})

-- Spiky --

Buff_Spiky = Base_Buff:New({

	AttributeName = "DamageReturnPower",
	Update = false,

	GetInfo = function(self, Effect)
		return "Damage return power increased by [c green]" .. self:GetChange(Effect.Level) .. "%"
	end,
})

-- Fortune --

Buff_Fortune = Base_Buff:New({

	Update = false,

	GetInfo = function(self, Effect)
		return "Blessed with good fortune"
	end,

	Stats = function(self, Level, Source, Change)
		Change.GoldGained = self:GetChange(Level)
		Change.ExperienceGained = self:GetChange(Level)
		Change.DropRate = self:GetChange(Level)

		return Change
	end,
})
