-- ToME - Tales of Maj'Eyal
-- Copyright (C) 2009 - 2019 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org

-- TODO: update tactical information for these talents

-- Regen makes resting super slow
-- Looks weaker than the other options, but extra life is a more universally useful stat and mind save is generally lower for celestial classes.
newTalent{
	name = "Chant of Fortitude",
	type = {"celestial/chants-chants", 1},
	mode = "sustained",
	hide = true,
	require = divi_req1,
	points = 5,
	cooldown = 12,
	sustain_positive = 20,
	no_energy = true,
	dont_provide_pool = true,
	tactical = { DEFEND = 2 },
	range = 0,
	getResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 60) end,
	getLifePct = function(self, t) return self:combatTalentLimit(t, 1, 0.10, 0.20) end,
	sustain_slots = 'celestial_chant',
	activate = function(self, t)
		local power = t.getResists(self, t)
		game:playSoundNear(self, "talents/spell_generic2")

		local ret = {}
		self:talentTemporaryValue(ret, "combat_mentalresist", power)
		self:talentTemporaryValue(ret, "max_life", t.getLifePct(self, t)*self.max_life)
		ret.particle = self:addParticles(Particles.new("golden_shield", 1))

		if self:knowTalent(self.T_CHANT_ILLUMINATE) then
			local t2 = self:getTalentFromId(self.T_CHANT_ILLUMINATE)
			self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.LIGHT]=t2.getDamageOnMeleeHit(self, t2)})
			self:talentTemporaryValue(ret, "mana_regen", t2.getBonusRegen(self, t2))
			self:talentTemporaryValue(ret, "stamina_regen", t2.getBonusRegen(self, t2))
		end

		if self:knowTalent(self.T_CHANT_ADEPT) then
			local t2 = self:getTalentFromId(self.T_CHANT_ADEPT)
			self:talentTemporaryValue(ret, "lite", t2.getBonusLight(self, t2))
			t2.doCure(self, t2, "mental")
		end

		if self:knowTalent(self.T_CHANT_RADIANT) then
			local t2 = self:getTalentFromId(self.T_CHANT_RADIANT)
			self:talentTemporaryValue(ret, "inc_damage", {[DamageType.LIGHT] = t2.getLightDamageIncrease(self, t2), [DamageType.FIRE] = t2.getLightDamageIncrease(self, t2)})
		end

		return ret
	end,
	deactivate = function(self, t, p)
		self:removeParticles(p.particle)
		return true
	end,
	info = function(self, t)
		local saves = t.getResists(self, t)
		local life = t.getLifePct(self, t)
		return ([[You chant the glory of the Sun, granting you %d Mental Save and increasing your maximum life by %0.1f%% (Currently:  %d).
		You may only have one Chant active at once.
		The effects will increase with your Spellpower.]]):
		tformat(saves, life*100, life*self.max_life)
	end,
}

-- Physical and weapon protection Chant.
newTalent{
	name = "Chant of Fortress",
	type = {"celestial/chants-chants", 1},
	mode = "sustained",
	hide = true,
	require = divi_req1,
	points = 5,
	cooldown = 12,
	sustain_positive = 20,
	no_energy = true,
	dont_provide_pool = true,
	tactical = { DEFEND = 2 },
	range = 0,
	getPhysicalResistance = function(self, t) return math.floor(self:combatTalentSpellDamage(t, 8, 25)) end,
	getResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 60) end,
	sustain_slots = 'celestial_chant',
	activate = function(self, t)
		local power = t.getResists(self, t)
		game:playSoundNear(self, "talents/spell_generic2")
		local ret = {}
		self:talentTemporaryValue(ret, "resists", {[DamageType.PHYSICAL] = t.getPhysicalResistance(self, t)})
		self:talentTemporaryValue(ret, "combat_physresist", power)
		self:talentTemporaryValue(ret, "combat_armor", t.getPhysicalResistance(self, t))
		self:talentTemporaryValue(ret, "combat_armor_hardiness", 15)
		ret.particle = self:addParticles(Particles.new("golden_shield", 1))

		if self:knowTalent(self.T_CHANT_ILLUMINATE) then
			local t2 = self:getTalentFromId(self.T_CHANT_ILLUMINATE)
			self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.LIGHT]=t2.getDamageOnMeleeHit(self, t2)})
			self:talentTemporaryValue(ret, "mana_regen", t2.getBonusRegen(self, t2))
			self:talentTemporaryValue(ret, "stamina_regen", t2.getBonusRegen(self, t2))
		end

		if self:knowTalent(self.T_CHANT_ADEPT) then
			local t2 = self:getTalentFromId(self.T_CHANT_ADEPT)
			self:talentTemporaryValue(ret, "lite", t2.getBonusLight(self, t2))
			t2.doCure(self, t2, "physical")
		end

		if self:knowTalent(self.T_CHANT_RADIANT) then
			local t2 = self:getTalentFromId(self.T_CHANT_RADIANT)
			self:talentTemporaryValue(ret, "inc_damage", {[DamageType.LIGHT] = t2.getLightDamageIncrease(self, t2), [DamageType.FIRE] = t2.getLightDamageIncrease(self, t2)})
		end

		return ret
	end,
	deactivate = function(self, t, p)
		self:removeParticles(p.particle)
		return true
	end,
	info = function(self, t)
		local physicalresistance = t.getPhysicalResistance(self, t)
		local saves = t.getResists(self, t)
		return ([[You chant the glory of the Sun, granting you %d%% physical damage resistance, %d physical save, %d armour and +15%% armour hardiness.
		You may only have one Chant active at once.
		The effects will increase with your Spellpower.]]):
		tformat(physicalresistance, saves, physicalresistance)
	end,
}

-- Ranged and magic protection Chant
-- This can be swapped to reactively with a projectile already in the air
newTalent{
	name = "Chant of Resistance",
	type = {"celestial/chants-chants",1},
	mode = "sustained",
	hide = true,
	require = divi_req1,
	points = 5,
	cooldown = 12,
	sustain_positive = 20,
	dont_provide_pool = true,
	tactical = { DEFEND = 2 },
	no_energy = true,
	range = 0,
	getResists = function(self, t) return self:combatTalentSpellDamage(t, 10, 30) end,
	getDamageChange = function(self, t)
		return -self:combatTalentLimit(t, 50, 14, 30) -- Limit < 50% damage reduction
	end,
	getSpellResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 60) end,
	sustain_slots = 'celestial_chant',
	callbackOnTakeDamage = function(self, t, src, x, y, type, dam, tmp, no_martyr)
		if src and src.x and src.y then
			-- assume instantaneous projection and check range to source
			if core.fov.distance(self.x, self.y, src.x, src.y) > 2 then
				dam = dam * (100 + t.getDamageChange(self, t)) / 100
				print("[PROJECTOR] Chant of Resistance (source) dam", dam)
			end
		end
		return {dam=dam}
	end,
	activate = function(self, t)
		local elempower = t.getResists(self, t)
		local spell = t.getSpellResists(self, t)
		game:playSoundNear(self, "talents/spell_generic2")
		local ret = {}
		self:talentTemporaryValue(ret, "resists", {
			[DamageType.FIRE] = elempower,
			[DamageType.LIGHTNING] = elempower,
			[DamageType.ACID] = elempower,
			[DamageType.COLD] = elempower,
		})
		self:talentTemporaryValue(ret, "combat_spellresist", spell)
		ret.particle = self:addParticles(Particles.new("golden_shield", 1))

		if self:knowTalent(self.T_CHANT_ILLUMINATE) then
			local t2 = self:getTalentFromId(self.T_CHANT_ILLUMINATE)
			self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.LIGHT]=t2.getDamageOnMeleeHit(self, t2)})
			self:talentTemporaryValue(ret, "mana_regen", t2.getBonusRegen(self, t2))
			self:talentTemporaryValue(ret, "stamina_regen", t2.getBonusRegen(self, t2))
		end

		if self:knowTalent(self.T_CHANT_ADEPT) then
			local t2 = self:getTalentFromId(self.T_CHANT_ADEPT)
			self:talentTemporaryValue(ret, "lite", t2.getBonusLight(self, t2))
			t2.doCure(self, t2, "magical")
		end

		if self:knowTalent(self.T_CHANT_RADIANT) then
			local t2 = self:getTalentFromId(self.T_CHANT_RADIANT)
			self:talentTemporaryValue(ret, "inc_damage", {[DamageType.LIGHT] = t2.getLightDamageIncrease(self, t2), [DamageType.FIRE] = t2.getLightDamageIncrease(self, t2)})
		end

		return ret
	end,
	deactivate = function(self, t, p)
		self:removeParticles(p.particle)
		return true
	end,
	info = function(self, t)
		local resists = t.getResists(self, t)
		local saves = t.getSpellResists(self, t)
		local range = -t.getDamageChange(self, t)
		return ([[You chant the glory of the Sun, granting you %d%% fire, lightning, acid and cold damage resistance, %d spell save and reduces the damage from enemies 3 or more spaces away by %d%%.
	You may only have one Chant active at once.
	The effects will increase with your Spellpower.]]):
		tformat(resists, saves, range)
	end,
}

-- Depreciated, but retained for compatability.
newTalent{
	name = "Chant of Light",
	type = {"celestial/chants-chants", 4},
	mode = "sustained",
	require = divi_req4,
	points = 5,
	cooldown = 12,
	sustain_positive = 5,
	no_energy = true,
	dont_provide_pool = true,
	tactical = { BUFF = 2 },
	range = 0,
	getLightDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 20, 50) end,
	getLite = function(self, t) return math.floor(self:combatTalentScale(t, 2, 6, "log")) end,
	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
	sustain_slots = 'celestial_chant',
	activate = function(self, t)
		game:playSoundNear(self, "talents/spell_generic2")
		local ret = {
			onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.LIGHT]=t.getDamageOnMeleeHit(self, t)}),
			phys = self:addTemporaryValue("inc_damage", {[DamageType.LIGHT] = t.getLightDamageIncrease(self, t), [DamageType.FIRE] = t.getLightDamageIncrease(self, t)}),
			lite = self:addTemporaryValue("lite", t.getLite(self, t)),
			particle = self:addParticles(Particles.new("golden_shield", 1))
		}
		return ret
	end,
	deactivate = function(self, t, p)
		self:removeParticles(p.particle)
		self:removeTemporaryValue("on_melee_hit", p.onhit)
		self:removeTemporaryValue("inc_damage", p.phys)
		self:removeTemporaryValue("lite", p.lite)
		return true
	end,
	info = function(self, t)
		local damageinc = t.getLightDamageIncrease(self, t)
		local damage = t.getDamageOnMeleeHit(self, t)
		local lite = t.getLite(self, t)
		return ([[You chant the glory of the Sun, empowering your light and fire elemental attacks so that they do %d%% additional damage.
		In addition, this talent surrounds you with a shield of light, dealing %0.1f light damage to anything that hits you in melee.
		Your lite radius is also increased by %d.
		You may only have one Chant active at once and this Chant costs less power to sustain.
		The effects will increase with your Spellpower.]]):
		tformat(damageinc, damDesc(self, DamageType.LIGHT, damage), lite)
	end,
}


newTalent{
	name = "Chant Acolyte",
	type = {"celestial/chants", 1},
	require = divi_req1,
	points = 5,
	mode = "passive",
	positive = 0, -- forces learning of Positive pool
	passives = function(self, t)
		self:setTalentTypeMastery("celestial/chants-chants", self:getTalentMastery(t))
	end,
	on_learn = function(self, t)
		self:learnTalent(self.T_CHANT_OF_FORTITUDE, true, nil, {no_unlearn=true})
		self:learnTalent(self.T_CHANT_OF_FORTRESS, true, nil, {no_unlearn=true})
		self:learnTalent(self.T_CHANT_OF_RESISTANCE, true, nil, {no_unlearn=true})
	end,
	on_unlearn = function(self, t)
		self:unlearnTalent(self.T_CHANT_OF_FORTITUDE)
		self:unlearnTalent(self.T_CHANT_OF_FORTRESS)
		self:unlearnTalent(self.T_CHANT_OF_RESISTANCE)
	end,
	info = function(self, t)
		local ret = ""
		local old1 = self.talents[self.T_CHANT_OF_FORTITUDE]
		local old2 = self.talents[self.T_CHANT_OF_FORTRESS]
		local old3 = self.talents[self.T_CHANT_OF_RESISTANCE]
		self.talents[self.T_CHANT_OF_FORTITUDE] = (self.talents[t.id] or 0)
		self.talents[self.T_CHANT_OF_FORTRESS] = (self.talents[t.id] or 0)
		self.talents[self.T_CHANT_OF_RESISTANCE] = (self.talents[t.id] or 0)
		pcall(function() -- Be very paranoid, even if some addon or whatever manage to make that crash, we still restore values
			local t1 = self:getTalentFromId(self.T_CHANT_OF_FORTITUDE)
			local t2 = self:getTalentFromId(self.T_CHANT_OF_FORTRESS)
			local t3 = self:getTalentFromId(self.T_CHANT_OF_RESISTANCE)
			ret = ([[You have learned to sing the praises of the Sun, in the form of three defensive Chants.
			Chant of Fortitude: Increases your mental save by %d and maximum life by %d%%.
			Chant of Fortress: Increases your physical save by %d, your physical resistance by %d%%, your armour by %d and your armour hardiness by 15%%.
			Chant of Resistance: Increases you spell save by %d, your fire/cold/lightning/acid resistances by %d%% and reduces all damage that comes from distant enemies (3 spaces or more) by %d%%.
			You may only have one Chant active at a time.]]):
			tformat(t1.getResists(self, t1), t1.getLifePct(self, t1)*100, t2.getResists(self, t2), t2.getPhysicalResistance(self, t2), t2.getPhysicalResistance(self, t2), t3.getSpellResists(self, t3), t3.getResists(self, t3), t3.getDamageChange(self, t3))
		end)
		self.talents[self.T_CHANT_OF_FORTITUDE] = old1
		self.talents[self.T_CHANT_OF_FORTRESS] = old2
		self.talents[self.T_CHANT_OF_RESISTANCE] = old3
		return ret
	end,
}

-- Mana regen is given to make it a little more attractive to Anorithils.
-- Might also make some people consider Chants as an escort reward.
newTalent{
	name = "Chant Illuminate",
	type = {"celestial/chants", 2},
	require = divi_req2,
	points = 5,
	mode = "passive",
	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 50) end,
	getBonusRegen = function(self, t) return self:combatTalentSpellDamage(t, 10, 20) / 10 end,
	info = function(self, t)
		return ([[Your Chants now bathe you in a cloak of light, which increases your stamina and mana regenerations by %0.2f per turn and does %0.2f light damage to anyone who hits you in melee.
		These values scale with your Spellpower.]]):tformat(t.getBonusRegen(self, t), damDesc(self, DamageType.LIGHT, t.getDamageOnMeleeHit(self, t)))
	end,
}

-- Remember that Chants can be swapped instantly.
newTalent{
	name = "Chant Adept",
	type = {"celestial/chants", 3},
	require = divi_req3,
	points = 5,
	mode = "passive",
	getDebuffCures = function(self, t) return math.floor(self:combatTalentScale(t, 1, 1.8, 0.75)) end,
	getBonusLight = function(self, t) return math.floor(self:combatTalentScale(t, 0.75, 3.5, 0.75)) end,
	doCure = function(self, t, type)
		if self.turn_procs.resetting_talents then return false end  -- Avoid levelup screen cleanse exploit
		local cures = t.getDebuffCures(self, t)
		local effs = {}
		local force = {}
		local known = false

		-- Go through all temporary effects
		for eff_id, p in pairs(self.tmp) do
			local e = self.tempeffect_def[eff_id]
			if e.type == type and e.status == "detrimental" and e.subtype["cross tier"] then
				force[#force+1] = {"effect", eff_id}
			elseif e.type == type and e.status == "detrimental" then
				effs[#effs+1] = {"effect", eff_id}
			end
		end

		-- Cross tier effects are always removed and not part of the random game, otherwise it is a huge nerf to wild infusion
		for i = 1, #force do
			local eff = force[i]
			if eff[1] == "effect" then
				self:removeEffect(eff[2])
				known = true
			end
		end

		if cures > 0 then
			for i = 1, cures do
				if #effs == 0 then break end
				local eff = rng.tableRemove(effs)

				if eff[1] == "effect" then
					self:removeEffect(eff[2])
					known = true
				end
			end
		end
		if known then
			game.logSeen(self, "%s is cured!", self:getName():capitalize())
		end
	end,
	info = function(self, t)
		return ([[Your skill at Chanting now extends the cloak of light, increasing your light radius by %d.
		Also, when you start a new Chant, you will be cured of all cross-tier effects and cured of up to %d debuffs.
		Chant of Fortitude cures mental effects.
		Chant of Fortress cures physical effects.
		Chant of Resistance cures magical effects.]]):tformat(t.getBonusLight(self, t), t.getDebuffCures(self, t))
	end,
}

newTalent{
	name = "Chant Radiant",
	type = {"celestial/chants", 4},
	require = divi_req4,
	points = 5,
	mode = "passive",
	getLightDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 10, 30) end,
	getPos = function(self, t) return self:combatTalentScale(t, 2, 5) end,
	getTurnLimit = function(self, t) return self:combatTalentScale(t, 1, 3) end,
	callbackOnMeleeHit = function(self, t, src)
		if not (self:isTalentActive(self.T_CHANT_OF_FORTRESS) or self:isTalentActive(self.T_CHANT_OF_FORTITUDE) or self:isTalentActive(self.T_CHANT_OF_RESISTANCE)) then return end
		if src == self then return end
		if self.turn_procs.chant_radiant and self.turn_procs.chant_radiant > t.getTurnLimit(self, t) then return end
		self.turn_procs.chant_radiant = self.turn_procs.chant_radiant or 0
		self:incPositive(t.getPos(self, t))
		self.turn_procs.chant_radiant = self.turn_procs.chant_radiant + 1
	end,
	callbackOnArcheryHit = function(self, t, dam, src)
		if not (self:isTalentActive(self.T_CHANT_OF_FORTRESS) or self:isTalentActive(self.T_CHANT_OF_FORTITUDE) or self:isTalentActive(self.T_CHANT_OF_RESISTANCE)) then return end
		if src == self then return end
		if self.turn_procs.chant_radiant and self.turn_procs.chant_radiant > t.getTurnLimit(self, t) then return end
		self.turn_procs.chant_radiant = self.turn_procs.chant_radiant or 0
		self:incPositive(t.getPos(self, t))
		self.turn_procs.chant_radiant = self.turn_procs.chant_radiant + 1
	end,
	info = function(self, t)
		return ([[Your passion for singing the praises of the Sun reaches its zenith.
		Your Chanting now increases your light and fire damage by %d%% and up to %d times per turn, when you are hit by a weapon attack, you will gain %0.1f Positive.
		These values scale with your Spellpower.]]):tformat(t.getLightDamageIncrease(self, t), t.getTurnLimit(self, t), t.getPos(self, t))
	end,
}