From e38f61a50c1294096dadcc6bd132eeba448799d0 Mon Sep 17 00:00:00 2001
From: grayswandir <grayswandir76@gmail.com>
Date: Sun, 30 Nov 2014 11:30:24 -0500
Subject: [PATCH] Added a system for defining mutually incompatible sustains.

example: sustain_slots = 'celestial_chant'
Changed most sustains to use the system.
Talent tooltips will show if they will deactivate anything.
---
 game/modules/tome/class/Actor.lua             | 54 +++++++++++++++++--
 .../tome/data/talents/celestial/chants.lua    | 19 ++-----
 .../tome/data/talents/celestial/hymns.lua     | 17 ++----
 .../tome/data/talents/cursed/endless-hunt.lua | 23 ++++----
 .../tome/data/talents/cursed/slaughter.lua    | 14 ++---
 .../tome/data/talents/cursed/strife.lua       | 21 ++++----
 .../tome/data/talents/spells/acid-alchemy.lua |  2 +-
 .../data/talents/spells/energy-alchemy.lua    |  2 +-
 .../tome/data/talents/spells/fire-alchemy.lua |  4 +-
 .../data/talents/spells/frost-alchemy.lua     |  2 +-
 .../tome/data/talents/spells/spells.lua       | 10 ----
 .../tome/data/talents/techniques/archery.lua  |  4 +-
 12 files changed, 90 insertions(+), 82 deletions(-)

diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 51923c1f1f..1b69545cd1 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -5049,6 +5049,16 @@ function _M:postUseTalent(ab, ret, silent)
 			if ab.sustain_feedback then
 				trigger = true; self:incMaxFeedback(-util.getval(ab.sustain_feedback, self, ab))
 			end
+			if ab.sustain_slots then
+				if not self.sustain_slots then self.sustain_slots = {} end
+				local slots = ab.sustain_slots
+				if 'string' == type(slots) then slots = {slots} end
+				for _, slot in pairs(slots) do
+					local t = self.sustain_slots[slot]
+					if t and self:isTalentActive(t) then self:forceUseTalent(t, {ignore_energy=true}) end
+					self.sustain_slots[slot] = ab.id
+				end
+			end
 			for event, store in pairs(sustainCallbackCheck) do
 				if ab[event] then
 					self[store] = self[store] or {}
@@ -5088,6 +5098,15 @@ function _M:postUseTalent(ab, ret, silent)
 			end
 			if ab.sustain_feedback then
 				self:incMaxFeedback(util.getval(ab.sustain_feedback, self, ab))
+				end
+			if ab.sustain_slots then
+				local slots = ab.sustain_slots
+				if 'string' == type(slots) then slots = {slots} end
+				for _, slot in pairs(slots) do
+					if self.sustain_slots[slot] == ab.id then
+						self.sustain_slots[slot] = nil
+					end
+				end
 			end
 			for event, store in pairs(sustainCallbackCheck) do
 				if ab[event] then
@@ -5200,6 +5219,25 @@ function _M:postUseTalent(ab, ret, silent)
 	return true
 end
 
+-- Return the talent currently taking up a given sustain slot.
+function _M:getSustainSlot(slot)
+	if not self.sustain_slots then return end
+	return self.sustain_slots[slot]
+end
+
+-- Get the sustain which a talent will replace.
+function _M:getReplacedSustains(talent)
+	if 'string' == type(talent) then talent = self:getTalentFromId(talent) end
+	local slots = talent.sustain_slots or {}
+	if 'string' == type(slots) then slots = {slots} end
+	local ret = {}
+	for _, slot in pairs(slots) do
+		local t = self:getSustainSlot(slot)
+		if t ~= talent.id then table.insert(ret, t) end
+	end
+	return ret
+end
+
 --- Force a talent to activate without using energy or such
 function _M:forceUseTalent(t, def)
 	if def.no_talent_fail then self:attr("no_talent_fail", 1) end
@@ -5393,6 +5431,14 @@ function _M:getTalentFullDescription(t, addlevel, config, fake_mastery)
 		end
 	end
 
+	if t.mode == 'sustained' then
+		local replaces = self:getReplacedSustains(t)
+		if #replaces > 0 then
+			for k, v in pairs(replaces) do replaces[k] = self:getTalentFromId(v).name end
+			d:add({"color",0x6f,0xff,0x83}, "Will Deactivate: ", {"color",0xFF,0xFF,0xFF}, table.concat(replaces, ', '), true)
+		end
+	end
+
 	self:triggerHook{"Actor:getTalentFullDescription", str=d, t=t, addlevel=addlevel, config=config, fake_mastery=fake_mastery}
 
 	d:add({"color",0x6f,0xff,0x83}, "Description: ", {"color",0xFF,0xFF,0xFF})
@@ -5436,12 +5482,12 @@ function _M:getTalentCooldown(t)
 	if eff and not self:attr("talent_reuse") then
 		cd = 1 + cd * eff.power
 	end
-	
+
 	local p = self:isTalentActive(self.T_MATRIX)
 	if p and p.talent == t.id then
 		cd = math.floor(cd * (1 - self:callTalent(self.T_MATRIX, "getPower")))
 	end
-	
+
 	if t.is_spell then
 		return math.ceil(cd * (1 - (self.spell_cooldown_reduction or 0)))
 	elseif t.is_summon then
@@ -5462,9 +5508,9 @@ function _M:startTalentCooldown(t, v)
 	else
 		if not t.cooldown then return end
 		self.talents_cd[t.id] = self:getTalentCooldown(t)
-		
+
 		if t.id ~= self.T_REDUX and self:hasEffect(self.EFF_REDUX) then
-			local eff = self:hasEffect(self.EFF_REDUX) 
+			local eff = self:hasEffect(self.EFF_REDUX)
 			if t.type[1]:find("^chronomancy/") and self:getTalentCooldown(t) <= eff.max_cd and t.mode == "activated" and not t.fixed_cooldown then
 				self.talents_cd[t.id] = 1
 			end
diff --git a/game/modules/tome/data/talents/celestial/chants.lua b/game/modules/tome/data/talents/celestial/chants.lua
index e8d0d4ac7e..4210aeb0f4 100644
--- a/game/modules/tome/data/talents/celestial/chants.lua
+++ b/game/modules/tome/data/talents/celestial/chants.lua
@@ -17,15 +17,6 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
-local function cancelChants(self)
-	local chants = {self.T_CHANT_OF_FORTITUDE, self.T_CHANT_OF_FORTRESS, self.T_CHANT_OF_RESISTANCE, self.T_CHANT_OF_LIGHT}
-	for i, t in ipairs(chants) do
-		if self:isTalentActive(t) then
-			self:forceUseTalent(t, {ignore_energy=true})
-		end
-	end
-end
-
 -- Synergizes with melee classes (escort), Weapon of Wrath, healing mod (avoid overheal > healing efficiency), and low spellpower
 newTalent{
 	name = "Chant of Fortitude",
@@ -42,11 +33,11 @@ newTalent{
 	getResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 70) end,
 	getLifePct = function(self, t) return self:combatTalentLimit(t, 1, 0.05, 0.20) end, -- Limit < 100% bonus
 	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
+	sustain_slots = 'celestial_chant',
 	activate = function(self, t)
-		cancelChants(self)
 		local power = t.getResists(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("combat_physresist", power),
@@ -95,8 +86,8 @@ newTalent{
 	getDamageChange = function(self, t)
 		return -self:combatTalentLimit(t, 50, 14, 30) -- Limit < 50% damage reduction
 	end,
+	sustain_slots = 'celestial_chant',
 	activate = function(self, t)
-		cancelChants(self)
 		game:playSoundNear(self, "talents/spell_generic2")
 		local ret = {
 			onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.LIGHT]=t.getDamageOnMeleeHit(self, t)}),
@@ -137,8 +128,8 @@ newTalent{
 	range = 10,
 	getResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
 	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
+	sustain_slots = 'celestial_chant',
 	activate = function(self, t)
-		cancelChants(self)
 		local power = t.getResists(self, t)
 		game:playSoundNear(self, "talents/spell_generic2")
 		local ret = {
@@ -182,8 +173,8 @@ newTalent{
 	getLightDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 20, 50) end,
 	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
 	getLite = function(self, t) return math.floor(self:combatTalentScale(t, 2, 6, "log")) end,
+	sustain_slots = 'celestial_chant',
 	activate = function(self, t)
-		cancelChants(self)
 		game:playSoundNear(self, "talents/spell_generic2")
 		local ret = {
 			onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.LIGHT]=t.getDamageOnMeleeHit(self, t)}),
diff --git a/game/modules/tome/data/talents/celestial/hymns.lua b/game/modules/tome/data/talents/celestial/hymns.lua
index 5e2c8e3f88..644fa2afae 100644
--- a/game/modules/tome/data/talents/celestial/hymns.lua
+++ b/game/modules/tome/data/talents/celestial/hymns.lua
@@ -17,15 +17,6 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
-local function cancelHymns(self)
-	local hymns = {self.T_HYMN_OF_SHADOWS, self.T_HYMN_OF_DETECTION, self.T_HYMN_OF_PERSEVERANCE, self.T_HYMN_OF_MOONLIGHT}
-	for i, t in ipairs(hymns) do
-		if self:isTalentActive(t) then
-			self:forceUseTalent(t, {ignore_energy=true})
-		end
-	end
-end
-
 newTalent{
 	name = "Hymn of Shadows",
 	type = {"celestial/hymns", 1},
@@ -40,8 +31,8 @@ newTalent{
 	range = 10,
 	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
 	getDarknessDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
+	sustain_slots = 'celestial_hymn',
 	activate = function(self, t)
-		cancelHymns(self)
 		game:playSoundNear(self, "talents/spell_generic2")
 		local ret = {
 			onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.DARKNESS]= t.getDamageOnMeleeHit(self, t)}),
@@ -83,8 +74,8 @@ newTalent{
 	getSeeInvisible = function(self, t) return self:combatTalentSpellDamage(t, 2, 35) end,
 	getSeeStealth = function(self, t) return self:combatTalentSpellDamage(t, 2, 15) end,
 	getInfraVisionPower = function(self, t) return math.floor(self:combatTalentScale(t, 6, 10)) end,
+	sustain_slots = 'celestial_hymn',
 	activate = function(self, t)
-		cancelHymns(self)
 		game:playSoundNear(self, "talents/spell_generic2")
 		local ret = {
 			onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.DARKNESS]= t.getDamageOnMeleeHit(self, t)}),
@@ -130,8 +121,8 @@ newTalent{
 	range = 10,
 	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
 	getImmunities = function(self, t) return self:combatTalentLimit(t, 1, 0.22, 0.5) end, -- Limit < 100%
+	sustain_slots = 'celestial_hymn',
 	activate = function(self, t)
-		cancelHymns(self)
 		local dam = self:combatTalentSpellDamage(t, 5, 25)
 		game:playSoundNear(self, "talents/spell_generic2")
 		local ret = {
@@ -205,8 +196,8 @@ newTalent{
 			self:incNegative(-drain)
 		end
 	end,
+	sustain_slots = 'celestial_hymn',
 	activate = function(self, t)
-		cancelHymns(self)
 		game:playSoundNear(self, "talents/spell_generic")
 		game.logSeen(self, "#DARK_GREY#A shroud of shadow dances around %s!", self.name)
 		return {
diff --git a/game/modules/tome/data/talents/cursed/endless-hunt.lua b/game/modules/tome/data/talents/cursed/endless-hunt.lua
index b9e62c77b2..ce6cd62ea6 100644
--- a/game/modules/tome/data/talents/cursed/endless-hunt.lua
+++ b/game/modules/tome/data/talents/cursed/endless-hunt.lua
@@ -221,22 +221,19 @@ newTalent{
 		if self ~= game.player and (self:isTalentActive(self.T_CLEAVE) or self:isTalentActive(self.T_REPEL)) then return false end
 		return true
 	end,
+	sustain_slots = 'cursed_combat_style',
 	activate = function(self, t)
-		-- deactivate other talents and place on cooldown
-		if self:isTalentActive(self.T_CLEAVE) then
-			self:useTalent(self.T_CLEAVE)
-		elseif self:knowTalent(self.T_CLEAVE) then
-			local tCleave = self:getTalentFromId(self.T_CLEAVE)
-			self.talents_cd[self.T_CLEAVE] = tCleave.cooldown
-		end
-
-		if self:isTalentActive(self.T_REPEL) then
-			self:useTalent(self.T_REPEL)
-		elseif self:knowTalent(self.T_REPEL) then
+		-- Place other talents on cooldown.
+		if self:knowTalent(self.T_REPEL) and not self:isTalentActive(self.T_REPEL) then
 			local tRepel = self:getTalentFromId(self.T_REPEL)
 			self.talents_cd[self.T_REPEL] = tRepel.cooldown
 		end
 
+		if self:knowTalent(self.T_CLEAVE) and not self:isTalentActive(self.T_CLEAVE) then
+			local tCleave = self:getTalentFromId(self.T_CLEAVE)
+			self.talents_cd[self.T_CLEAVE] = tCleave.cooldown
+		end
+
 		local movementSpeedChange = t.getMovementSpeedChange(self, t)
 		return {
 			moveId = self:addTemporaryValue("movement_speed", movementSpeedChange),
@@ -252,8 +249,8 @@ newTalent{
 	info = function(self, t)
 		local movementSpeedChange = t.getMovementSpeedChange(self, t)
 		local defenseChange = t.getDefenseChange(self, t, true)
-		return ([[Let hate fuel your movements. While active, you gain %d%% movement speed. The recklessness of your movement brings you bad luck (Luck -3). 
-		Cleave, Repel and Surge cannot be active simultaneously, and activating one will place the others in cooldown. 
+		return ([[Let hate fuel your movements. While active, you gain %d%% movement speed. The recklessness of your movement brings you bad luck (Luck -3).
+		Cleave, Repel and Surge cannot be active simultaneously, and activating one will place the others in cooldown.
 		The speed of your movements, combined with the balance and utility of two weapons, gives you %d extra Defense while dual-wielding.
 		Movement speed and dual-wielding Defense both increase with with the Willpower stat.]]):format(movementSpeedChange * 100, defenseChange)
 	end,
diff --git a/game/modules/tome/data/talents/cursed/slaughter.lua b/game/modules/tome/data/talents/cursed/slaughter.lua
index 6596840224..59f5d03ed1 100644
--- a/game/modules/tome/data/talents/cursed/slaughter.lua
+++ b/game/modules/tome/data/talents/cursed/slaughter.lua
@@ -303,18 +303,15 @@ newTalent{
 		if self ~= game.player and (self:isTalentActive(self.T_SURGE) or self:isTalentActive(self.T_REPEL)) then return false end
 		return true
 	end,
+	sustain_slots = 'cursed_combat_style',
 	activate = function(self, t)
-		-- deactivate other talents and place on cooldown
-		if self:isTalentActive(self.T_SURGE) then
-			self:useTalent(self.T_SURGE)
-		elseif self:knowTalent(self.T_SURGE) then
+		-- Place other talents on cooldown.
+		if self:knowTalent(self.T_SURGE) and not self:isTalentActive(self.T_SURGE) then
 			local tSurge = self:getTalentFromId(self.T_SURGE)
 			self.talents_cd[self.T_SURGE] = tSurge.cooldown
 		end
 
-		if self:isTalentActive(self.T_REPEL) then
-			self:useTalent(self.T_REPEL)
-		elseif self:knowTalent(self.T_REPEL) then
+		if self:knowTalent(self.T_REPEL) and not self:isTalentActive(self.T_REPEL) then
 			local tRepel = self:getTalentFromId(self.T_REPEL)
 			self.talents_cd[self.T_REPEL] = tRepel.cooldown
 		end
@@ -353,10 +350,9 @@ newTalent{
 	info = function(self, t)
 		local chance = t.getChance(self, t, 0)
 		local chance2h = t.getChance(self, t, 1)
-		return ([[While active, every swing of your weapon has a %d%% (if one-handed) or %d%% (if two-handed) chance of striking a second nearby target for %d%% (at 0 Hate) to %d%% (at 100+ Hate) damage (+25%% for two-handed weapons). The recklessness of your attacks brings you bad luck (luck -3). 
+		return ([[While active, every swing of your weapon has a %d%% (if one-handed) or %d%% (if two-handed) chance of striking a second nearby target for %d%% (at 0 Hate) to %d%% (at 100+ Hate) damage (+25%% for two-handed weapons). The recklessness of your attacks brings you bad luck (luck -3).
 		Cleave, Repel and Surge cannot be active simultaneously, and activating one will place the others in cooldown.
 		The Cleave chance and damage increase with your Strength.]]):
 		format(chance, chance2h, t.getDamageMultiplier(self, t, 0) * 100, t.getDamageMultiplier(self, t, 100) * 100)
 	end,
 }
-
diff --git a/game/modules/tome/data/talents/cursed/strife.lua b/game/modules/tome/data/talents/cursed/strife.lua
index 3cd2ec125d..5acfe5dcaf 100644
--- a/game/modules/tome/data/talents/cursed/strife.lua
+++ b/game/modules/tome/data/talents/cursed/strife.lua
@@ -378,22 +378,19 @@ newTalent{
 		if self ~= game.player and (self:isTalentActive(self.T_CLEAVE) or self:isTalentActive(self.T_SURGE)) then return false end
 		return true
 	end,
+	sustain_slots = 'cursed_combat_style',
 	activate = function(self, t)
-		-- deactivate other talents and place on cooldown
-		if self:isTalentActive(self.T_CLEAVE) then
-			self:useTalent(self.T_CLEAVE)
-		elseif self:knowTalent(self.T_CLEAVE) then
-			local tCleave = self:getTalentFromId(self.T_CLEAVE)
-			self.talents_cd[self.T_CLEAVE] = tCleave.cooldown
-		end
-
-		if self:isTalentActive(self.T_SURGE) then
-			self:useTalent(self.T_SURGE)
-		elseif self:knowTalent(self.T_SURGE) then
+		-- Place other talents on cooldown.
+		if self:knowTalent(self.T_SURGE) and not self:isTalentActive(self.T_SURGE) then
 			local tSurge = self:getTalentFromId(self.T_SURGE)
 			self.talents_cd[self.T_SURGE] = tSurge.cooldown
 		end
 
+		if self:knowTalent(self.T_CLEAVE) and not self:isTalentActive(self.T_CLEAVE) then
+			local tCleave = self:getTalentFromId(self.T_CLEAVE)
+			self.talents_cd[self.T_CLEAVE] = tCleave.cooldown
+		end
+
 		return {
 			luckId = self:addTemporaryValue("inc_stats", { [Stats.STAT_LCK] = -3 })
 		}
@@ -409,7 +406,7 @@ newTalent{
 	end,
 	info = function(self, t)
 		local chance = t.getChance(self, t)
-		return ([[Rather than hide from the onslaught, you face down every threat. While active you have a %d%% chance of repelling a melee attack. The recklessness of your defense brings you bad luck (Luck -3). 
+		return ([[Rather than hide from the onslaught, you face down every threat. While active you have a %d%% chance of repelling a melee attack. The recklessness of your defense brings you bad luck (Luck -3).
 		Cleave, Repel and Surge cannot be active simultaneously, and activating one will place the others in cooldown.
 		Repel chance increases with your Strength, and when equipped with a shield.]]):format(chance)
 	end,
diff --git a/game/modules/tome/data/talents/spells/acid-alchemy.lua b/game/modules/tome/data/talents/spells/acid-alchemy.lua
index 1ca07f4f58..29266225d5 100644
--- a/game/modules/tome/data/talents/spells/acid-alchemy.lua
+++ b/game/modules/tome/data/talents/spells/acid-alchemy.lua
@@ -28,8 +28,8 @@ newTalent{
 	cooldown = 30,
 	tactical = { BUFF = 2 },
 	getIncrease = function(self, t) return self:combatTalentScale(t, 0.05, 0.25) * 100 end,
+	sustain_slots = 'alchemy_infusion',
 	activate = function(self, t)
-		cancelAlchemyInfusions(self)
 		game:playSoundNear(self, "talents/arcane")
 		local ret = {}
 		self:talentTemporaryValue(ret, "inc_damage", {[DamageType.ACID] = t.getIncrease(self, t)})
diff --git a/game/modules/tome/data/talents/spells/energy-alchemy.lua b/game/modules/tome/data/talents/spells/energy-alchemy.lua
index 233d3f8a35..095aa2c10b 100644
--- a/game/modules/tome/data/talents/spells/energy-alchemy.lua
+++ b/game/modules/tome/data/talents/spells/energy-alchemy.lua
@@ -28,8 +28,8 @@ newTalent{
 	cooldown = 30,
 	tactical = { BUFF = 2 },
 	getIncrease = function(self, t) return self:combatTalentScale(t, 0.05, 0.25) * 100 end,
+	sustain_slots = 'alchemy_infusion',
 	activate = function(self, t)
-		cancelAlchemyInfusions(self)
 		game:playSoundNear(self, "talents/arcane")
 		local ret = {}
 		self:talentTemporaryValue(ret, "inc_damage", {[DamageType.LIGHTNING] = t.getIncrease(self, t)})
diff --git a/game/modules/tome/data/talents/spells/fire-alchemy.lua b/game/modules/tome/data/talents/spells/fire-alchemy.lua
index 45932baf69..068154f2f8 100644
--- a/game/modules/tome/data/talents/spells/fire-alchemy.lua
+++ b/game/modules/tome/data/talents/spells/fire-alchemy.lua
@@ -28,8 +28,8 @@ newTalent{
 	cooldown = 30,
 	tactical = { BUFF = 2 },
 	getIncrease = function(self, t) return self:combatTalentScale(t, 0.05, 0.25) * 100 end,
+	sustain_slots = 'alchemy_infusion',
 	activate = function(self, t)
-		cancelAlchemyInfusions(self)
 		game:playSoundNear(self, "talents/arcane")
 		local ret = {}
 		self:talentTemporaryValue(ret, "inc_damage", {[DamageType.FIRE] = t.getIncrease(self, t)})
@@ -95,7 +95,7 @@ newTalent{
 			self:project(tg, x, y, function(px, py)
 				local target = game.level.map(px, py, Map.ACTOR)
 				if target and not target:hasEffect(target.EFF_BURNING) and self:reactionToward(target) < 0 then
-					target:setEffect(target.EFF_BURNING, heat.dur + math.ceil(t.getDuration(self, t)/3), {src=self, power=heat.power}) 
+					target:setEffect(target.EFF_BURNING, heat.dur + math.ceil(t.getDuration(self, t)/3), {src=self, power=heat.power})
 				end
 			end)
 		end
diff --git a/game/modules/tome/data/talents/spells/frost-alchemy.lua b/game/modules/tome/data/talents/spells/frost-alchemy.lua
index 5bdecd6eac..460ed2efc5 100644
--- a/game/modules/tome/data/talents/spells/frost-alchemy.lua
+++ b/game/modules/tome/data/talents/spells/frost-alchemy.lua
@@ -28,8 +28,8 @@ newTalent{
 	cooldown = 30,
 	tactical = { BUFF = 2 },
 	getIncrease = function(self, t) return self:combatTalentScale(t, 0.05, 0.25) * 100 end,
+	sustain_slots = 'alchemy_infusion',
 	activate = function(self, t)
-		cancelAlchemyInfusions(self)
 		game:playSoundNear(self, "talents/arcane")
 		local ret = {}
 		self:talentTemporaryValue(ret, "inc_damage", {[DamageType.COLD] = t.getIncrease(self, t)})
diff --git a/game/modules/tome/data/talents/spells/spells.lua b/game/modules/tome/data/talents/spells/spells.lua
index dfacde99af..440a267f24 100644
--- a/game/modules/tome/data/talents/spells/spells.lua
+++ b/game/modules/tome/data/talents/spells/spells.lua
@@ -239,16 +239,6 @@ function necroEssenceDead(self, checkonly)
 end
 -------------------------------------------
 
-function cancelAlchemyInfusions(self)
-	local chants = {self.T_FIRE_INFUSION, self.T_FROST_INFUSION, self.T_ACID_INFUSION, self.T_LIGHTNING_INFUSION}
-	for i, t in ipairs(chants) do
-		if self:isTalentActive(t) then
-			self:forceUseTalent(t, {ignore_energy=true})
-		end
-	end
-end
-
-
 load("/data/talents/spells/arcane.lua")
 load("/data/talents/spells/aether.lua")
 load("/data/talents/spells/fire.lua")
diff --git a/game/modules/tome/data/talents/techniques/archery.lua b/game/modules/tome/data/talents/techniques/archery.lua
index a7385a2972..cd6c64d87e 100644
--- a/game/modules/tome/data/talents/techniques/archery.lua
+++ b/game/modules/tome/data/talents/techniques/archery.lua
@@ -177,6 +177,7 @@ newTalent{
 			apr = self:combatScale(self:getTalentLevel(t) * self:getDex(10, true), 3, 0, 53, 50)}
 		return vals
 	end,
+	sustain_slots = 'stance',
 	activate = function(self, t)
 		local weapon = self:hasArcheryWeapon()
 		if not weapon then
@@ -184,7 +185,6 @@ newTalent{
 			return nil
 		end
 
-		if self:isTalentActive(self.T_RAPID_SHOT) then self:forceUseTalent(self.T_RAPID_SHOT, {ignore_energy=true}) end
 		local vals = t.getCombatVals(self, t)
 		return {
 			speed = self:addTemporaryValue("combat_physspeed", vals.speed),
@@ -229,6 +229,7 @@ newTalent{
 			}
 		return vals
 	end,
+	sustain_slots = 'stance',
 	activate = function(self, t)
 		local weapon = self:hasArcheryWeapon()
 		if not weapon then
@@ -236,7 +237,6 @@ newTalent{
 			return nil
 		end
 
-		if self:isTalentActive(self.T_AIM) then self:forceUseTalent(self.T_AIM, {ignore_energy=true}) end
 		local vals = t.getCombatVals(self, t)
 		return {
 			speed = self:addTemporaryValue("combat_physspeed", vals.speed),
-- 
GitLab