diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 5bfc1612d3d4af706fca8358077790a27a81d145..a7b4d200fc6cb0fbaef247cbbe9506e4b178b7f6 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -519,8 +519,7 @@ function _M:actBase()
 	if self:knowTalent(self.T_DUAL_WEAPON_DEFENSE) then self:setEffect(self.EFF_DUAL_WEAPON_DEFENSE,1,{}) end
 	if self:knowTalent(self.T_COUNTER_ATTACK) then self:setEffect(self.EFF_COUNTER_ATTACKING,1,{}) end
 	if self:knowTalent(self.T_DEFENSIVE_THROW) then self:setEffect(self.EFF_DEFENSIVE_GRAPPLING,1,{}) end
-
-	-- Compute timed effects
+	
 	self:timedEffects()
 
 	-- Handle thunderstorm, even if the actor is stunned or incapacitated it still works
@@ -1305,11 +1304,6 @@ function _M:move(x, y, force)
 		self:forceUseTalent(self.T_BODY_OF_STONE, {ignore_energy=true})
 	end
 
-	-- Celerity
-	if moved and ox and oy and (ox ~= self.x or oy ~= self.y) and self:knowTalent(self.T_CELERITY) then
-		self:callTalent(self.T_CELERITY, "doCelerity")
-	end
-
 	-- Break channels
 	if moved then
 		self:breakPsionicChannel()
@@ -1454,8 +1448,7 @@ function _M:teleportRandom(x, y, dist, min_dist)
 
 	-- Dimensional Anchor, prevent teleports and deal damage
 	if self:hasEffect(self.EFF_DIMENSIONAL_ANCHOR) then
-		local p = self:hasEffect(self.EFF_DIMENSIONAL_ANCHOR)
-		DamageType:get(DamageType.WARP).projector(p.src or self, self.x, self.y, DamageType.WARP, p.damage)
+		self:callEffect(self.EFF_DIMENSIONAL_ANCHOR, "onTeleport")
 		return
 	end
 
@@ -1478,11 +1471,6 @@ function _M:teleportRandom(x, y, dist, min_dist)
 			self:callTalent(self.T_DIMENSIONAL_SHIFT, "doShift")
 		end
 
-		-- Teleportation does not clear Time Dilation
-		if self:isTalentActive(self.T_TIME_DILATION) then
-			self:callTalent(self.T_TIME_DILATION, "updateOnTeleport", ox, oy)
-		end
-
 		self.x, self.y, ox, oy = ox, oy, self.x, self.y
 	else
 		-- Phase Blast failure
@@ -2033,21 +2021,6 @@ function _M:onTakeHit(value, src, death_note)
 			return 0
 		end
 	end
-	if self:attr("phase_shift_chrono") and not self.turn_procs.phase_shift_chrono and value > self.max_life *0.1 then
-		self.turn_procs.phase_shift_chrono = true
-		local nx, ny = util.findFreeGrid(self.x, self.y, 5, true, {[Map.ACTOR]=true})
-		if nx then
-			local ox, oy = self.x, self.y
-			if not self:teleportRandom(nx, ny, 0) then
-				game.logSeen(self, "The spell fizzles!")
-			else
-				game.level.map:particleEmitter(ox, oy, 1, "temporal_teleport")
-				game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
-				game:delayedLogDamage(src or {}, self, 0, ("#STEEL_BLUE#(%d shifted)#LAST#"):format(value/2), nil)
-				value = value/2
-			end
-		end
-	end
 
 	if self:attr("retribution") then
 	-- Absorb damage into the retribution
@@ -2247,11 +2220,6 @@ function _M:onTakeHit(value, src, death_note)
 		end
 	end
 
-	-- Paradox Shield
-	if value > 0 and self:isTalentActive(self.T_PRESERVE_PATTERN) then
-		value = self:callTalent(self.T_PRESERVE_PATTERN, "doPerservePattern", src, value)
-	end
-
 	if value <=0 then return 0 end
 	if self.knowTalent and (self:knowTalent(self.T_SEETHE) or self:knowTalent(self.T_GRIM_RESOLVE)) then
 		if not self:hasEffect(self.EFF_CURSED_FORM) then
@@ -2983,7 +2951,7 @@ function _M:die(src, death_note)
 			p.src:project({type="ball", radius=4, x=self.x, y=self.y}, self.x, self.y, DamageType.TEMPORAL, p.explosion, nil)
 			game.level.map:particleEmitter(self.x, self.y, 4, "ball_temporal", {radius=4})
 		else
-			p.src:project({type="ball", radius=4, x=self.x, y=self.y}, self.x, self.y, DamageType.MATTER, p.explosion, nil)
+			p.src:project({type="ball", radius=4, x=self.x, y=self.y}, self.x, self.y, DamageType.WARP, p.explosion, nil)
 			game.level.map:particleEmitter(self.x, self.y, 4, "ball_matter", {radius=4})
 		end
 		game:playSoundNear(self, "talents/breath")
@@ -3006,8 +2974,8 @@ function _M:die(src, death_note)
 		end)
 	end
 
-	if self:hasEffect(self.EFF_TRIM_THREADS) then
-		local p = self:hasEffect(self.EFF_TRIM_THREADS)
+	if self:hasEffect(self.EFF_ATTENUATE) then
+		local p = self:hasEffect(self.EFF_ATTENUATE)
 		p.src:incParadox(-p.reduction)
 	end
 
@@ -3533,7 +3501,7 @@ function _M:actorCheckSustains()
 end
 
 -- Quick Switch Weapons
-function _M:quickSwitchWeapons(free_swap, message)
+function _M:quickSwitchWeapons(free_swap, message, silent)
 	if self.no_inventory_access then return end
 	local mh1, mh2 = self.inven[self.INVEN_MAINHAND], self.inven[self.INVEN_QS_MAINHAND]
 	local oh1, oh2 = self.inven[self.INVEN_OFFHAND], self.inven[self.INVEN_QS_OFFHAND]
@@ -3606,10 +3574,12 @@ function _M:quickSwitchWeapons(free_swap, message)
 	self:actorCheckSustains()
 
 	-- Special Messages
-	if message == "warden" then
-		game.logPlayer(self, "You teleport %s into your hands.", names)
-	else
-		game.logPlayer(self, "You switch your weapons to: %s.", names)
+	if not silent then
+		if message == "warden" then
+			game.logPlayer(self, "You teleport %s into your hands.", names)
+		else
+			game.logPlayer(self, "You switch your weapons to: %s.", names)
+		end
 	end
 
 	self.off_weapon_slots = not self.off_weapon_slots
@@ -4011,7 +3981,7 @@ function _M:canWearObject(o, try_slot)
 			end
 		end end
 	end
-	if o.type == "weapon" and self:knowTalent(self.T_STRENGTH_OF_PURPOSE) then
+	if (o.type == "weapon" or o.type == "ammo") and self:knowTalent(self.T_STRENGTH_OF_PURPOSE) then
 		oldreq = rawget(o, "require")
 		o.require = table.clone(oldreq or {}, true)
 		if o.require.stat and o.require.stat.str then
@@ -4064,6 +4034,7 @@ function _M:learnTalent(t_id, force, nb, extra)
 
 	if t.is_spell then self:attr("has_arcane_knowledge", nb or 1) end
 	if t.is_antimagic then self:attr("forbid_arcane", nb or 1) end
+	if t.type[1]:find("^chronomancy/bow") or t.type[1]:find("^chronomancy/blade") then self:attr("warden_swap", nb or 1) end
 
 	if t.dont_provide_pool then return true end
 
@@ -4242,6 +4213,7 @@ function _M:unlearnTalent(t_id, nb, no_unsustain, extra)
 
 	if t.is_spell then self:attr("has_arcane_knowledge", -nb) end
 	if t.is_antimagic then self:attr("forbid_arcane", -nb) end
+	if t.type[1]:find("^chronomancy/bow") or t.type[1]:find("^chronomancy/blade") then self:attr("warden_swap", -nb) end
 
 	-- If we learn mindslayer things we learn telekinetic grasp & beyond the flesh
 	if t.autolearn_mindslayer then
@@ -4300,32 +4272,41 @@ end
 -- This handles anomalies
 -- Reduction is the Paradox recovered
 -- Anomaly Type is used to force an anomaly type for the talent, generally set to ab.anomaly_type
--- Chance use this for the anomaly chance, generally set to getAnomalyChance() or "forced"
+-- Chance use this for the anomaly chance, generally set to paradoxFailChance() or "forced"
 -- Target, if we're forcing an anomaly target
 function _M:paradoxDoAnomaly(reduction, anomaly_type, chance, target, silent)
 	local anomaly_type = anomaly_type or "random"
-	local forced = false
 	local chance = chance or self:paradoxFailChance()
-	if chance == "forced" then
-		forced = true
-		chance = 100
+	if chance == "forced" then chance = 100	end
+	
+	-- Anomaly biases can be set manually for monsters or classes
+	-- Use the following format anomaly_bias = { type = "teleport", chance=50}
+	-- Additionally anomaly biases could be set by a talent; see the data/chats/chromonacy-bias-weave for an example
+	local function check_bias(major)
+		if self.anomaly_bias then
+			local bias_chance = self.anomaly_bias.chance
+			if rng.percent(bias_chance) then 
+				anomaly_type = self.anomaly_bias.type
+				return true
+			end
+		end
 	end
 
 	-- See if we create an anomaly
 	if not game.zone.no_anomalies and not self:attr("no_paradox_fail") then
-		if not forced and self.turn_procs.anomalies_checked then return false end  -- This is so players can't chain cancel out of targeting to trigger anomalies on purpose, we clear it out in postUse
-		if not forced then self.turn_procs.anomalies_checked = true end
+		-- This is so players can't chain cancel out of targeting to trigger anomalies on purpose, we clear it out in postUse
+		if not chance == 100 and self.turn_procs.anomalies_checked then return false end  
+		if not chance == 100 then self.turn_procs.anomalies_checked = true end
 
-		-- return true if we roll an anomly
 		if rng.percent(chance) then
+			local anomaly_triggered = true
+			
 			-- If our Paradox is over 600 do a major anomaly
-			if anomaly_type ~= "no-major" and self:getModifiedParadox() > 600 then
+			if anomaly_type ~= "no-major" and (anomaly_type == "major" or self:getModifiedParadox() > 600) then
 				anomaly_type = "major"
 			else
 				-- Check for Bias?
-				if self.anomaly_bias and rng.percent(self.anomaly_bias.chance) then anomaly_type = self.anomaly_bias.type end
-				-- Revert no-major to random
-				if anomaly_type == "no-major" then anomaly_type = "random" end
+				if not check_bias(true) then anomaly_type ="random" end
 			end
 
 			-- Now pick anomalies filtered by type
@@ -4338,33 +4319,40 @@ function _M:paradoxDoAnomaly(reduction, anomaly_type, chance, target, silent)
 				end
 			end
 
-			-- Did we find anomalies?
+			-- Be sure we found an anomly first
 			if ts[1] then
-				-- Do we have a target?  If not we pass to anomaly targeting
-				-- The ignore energy calls here allow anomalies to be cast even when it's not the players turn
-				if target then
-					self:attr("anomaly_forced_target", 1)
-					self:forceUseTalent(rng.table(ts), {ignore_energy=true, force_target=target})
-					self:attr("anomaly_forced_target", -1)
+				local anomaly = rng.table(ts)
+				
+				if self:knowTalent(self.T_TWIST_FATE) and not self:isTalentCoolingDown(self.T_TWIST_FATE) and anomaly_type ~= "major" then
+					if self:hasEffect(self.EFF_TWIST_FATE) then
+						self:callTalent(self.T_TWIST_FATE, "doTwistFate")
+						self:callTalent(self.T_TWIST_FATE, "setEffect", anomaly, reduction)
+					else
+						self:callTalent(self.T_TWIST_FATE, "setEffect", anomaly, reduction)
+						anomaly_triggered = false
+					end
 				else
-					self:forceUseTalent(rng.table(ts), {ignore_energy=true})
+					--self:forceUseTalent(anomaly, {ignore_energy=true})
+					self:forceUseTalent(anomaly, {force_target=target or self})
 				end
 			end
 
-			-- Drop some game messages; these happen so Paradox gets reduced even if an anomaly isn't found
-			if not silent then
-				if forced then
-					game.logPlayer(self, "#STEEL_BLUE#You've moved to another time thread.")
-				else
-					game.logPlayer(self, "#LIGHT_RED#You lose control and unleash an anomaly!")
+			-- reduce paradox and handle messages
+			if anomaly_triggered then
+				if not silent then
+					if chance == 100 then
+						game.logPlayer(self, "#STEEL_BLUE#You've moved to another time thread.")
+					else
+						game.logPlayer(self, "#LIGHT_RED#You lose control and unleash an anomaly!")
+					end
+				end
+				-- Reduce Paradox
+				if reduction and reduction > 0 then
+					self:incParadox(-reduction)
 				end
-			end
-			-- Reduce Paradox
-			if reduction and reduction > 0 then
-				self:incParadox(-reduction)
 			end
 
-			return true
+			return anomaly_triggered
 		end
 	end
 end
@@ -4654,8 +4642,6 @@ function _M:preUseTalent(ab, silent, fake)
 		if cost > 0 then
 			local multi = 2 + (self:attr("anomaly_paradox_recovery") or 0)
 			if self:paradoxDoAnomaly(cost * multi, ab.anomaly_type or nil, self:paradoxFailChance(), nil, silent) then
-				local speed = math.max(0, 1 - (self:attr("anomaly_recovery_speed") or 0))
-				self:useEnergy(game.energy_to_act * speed)
 				game:playSoundNear(self, "talents/dispel")
 				return false
 			end
@@ -4759,6 +4745,7 @@ local sustainCallbackCheck = {
 	callbackOnTemporaryEffect = "talents_on_tmp",
 	callbackOnTalentDisturbed = "talents_on_talent_disturbed",
 	callbackOnBlock = "talents_on_block",
+	callbackOnChronoWeaponFoldingHit = "talents_on_chrono_weapon_folding_hit",
 }
 _M.sustainCallbackCheck = sustainCallbackCheck
 
@@ -5118,7 +5105,7 @@ function _M:postUseTalent(ab, ret, silent)
 	if self:triggerHook(hd) then
 		trigger = hd.trigger
 	end
-
+	
 	self:fireTalentCheck("callbackOnTalentPost", ab, ret, silent)
 
 	if trigger and self:hasEffect(self.EFF_BURNING_HEX) and not self:attr("talent_reuse") then
diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua
index 922e748fd0ca959fd6b52777e1930642a86ce28e..4ee91e8c6901b6305957228761b504d26af27f7c 100644
--- a/game/modules/tome/class/Object.lua
+++ b/game/modules/tome/class/Object.lua
@@ -60,7 +60,7 @@ function _M:getRequirementDesc(who)
 		self.require = oldreq
 
 		return desc
-	elseif self.type =="weapon" and type(self.require) == "table" and who:knowTalent(who.T_STRENGTH_OF_PURPOSE) then
+	elseif (self.type =="weapon" or self.type=="ammo") and type(self.require) == "table" and who:knowTalent(who.T_STRENGTH_OF_PURPOSE) then
 		local oldreq = rawget(self, "require")
 		self.require = table.clone(oldreq, true)
 		if self.require.stat and self.require.stat.str then
@@ -1622,7 +1622,7 @@ function _M:getTextualDesc(compare_with, use_actor)
 		desc:add(talents[tid][3] and {"color","GREEN"} or {"color","WHITE"}, ("Talent on hit(mindpower): %s (%d%% chance level %d)."):format(self:getTalentFromId(tid).name, talents[tid][1], talents[tid][2]), {"color","LAST"}, true)
 	end
 
-	if self.use_no_energy then
+	if self.use_no_energy and not self.use_no_energy == "fake" then
 		desc:add("Activating this item is instant.", true)
 	end
 
diff --git a/game/modules/tome/class/interface/Archery.lua b/game/modules/tome/class/interface/Archery.lua
index 8cc6bd0cfb2be205035b870a53917acba93fe2e2..0427156a4e4ebd6a9cc6d9b1bfef16aba1a6b3b4 100644
--- a/game/modules/tome/class/interface/Archery.lua
+++ b/game/modules/tome/class/interface/Archery.lua
@@ -75,7 +75,7 @@ function _M:archeryAcquireTargets(tg, params)
 	print("[PROJECTILE SPEED] ::", tg.speed)
 
 	self:triggerHook{"Combat:archeryTargetKind", tg=tg, params=params, mode="target"}
-
+	
 	local x, y = params.x, params.y
 	if not x or not y then x, y = self:getTarget(tg) end
 	if not x or not y then return nil end
@@ -184,6 +184,15 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 	local mult = tg.archery.mult or 1
 
 	self.turn_procs.weapon_type = {kind=weapon and weapon.talented or "unknown", mode="archery"}
+	
+	-- Warden's Focus
+	if self:hasEffect(self.EFF_WARDEN_S_FOCUS) then
+		local eff = self:hasEffect(self.EFF_WARDEN_S_FOCUS)
+		if target == eff.target then
+			tg.archery.atk = (tg.archery.atk or 0) + eff.atk
+			tg.archery.crit = (tg.archery.crit or 0) + eff.crit
+		end
+	end
 
 	-- Does the blow connect? yes .. complex :/
 	if tg.archery.use_psi_archery then self:attr("use_psi_combat", 1) end
@@ -384,6 +393,11 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 			t.proc(self, t, target, weapon)
 		end
 	end
+	
+	-- Temporal Cast
+	if hitted and self:knowTalent(self.T_WEAPON_FOLDING) and self:isTalentActive(self.T_WEAPON_FOLDING) then
+		self:callTalent(self.T_WEAPON_FOLDING, "doWeaponFolding", target)
+	end
 
 	-- Special effect
 	if hitted and weapon and weapon.special_on_hit and weapon.special_on_hit.fct and (not target.dead or weapon.special_on_hit.on_kill) then
@@ -426,31 +440,6 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 		self.shattering_impact_last_turn = game.turn
 	end
 
-	-- Temporal cast
-	if hitted and self:knowTalent(self.T_WEAPON_FOLDING) and self:isTalentActive(self.T_WEAPON_FOLDING) then
-		local dam = self:callTalent(self.T_WEAPON_FOLDING, "getDamage")
-		if self:knowTalent(self.T_FRAYED_THREADS) then
-			local burst_damage = dam * self:callTalent(self.T_FRAYED_THREADS, "getPercent")
-			local burst_radius = self:callTalent(self.T_FRAYED_THREADS, "getRadius")
-			self:project({type="ball", radius=burst_radius, friendlyfire=false}, target.x, target.y, DamageType.TEMPORAL, burst_damage)
-		end
-		if dam > 0 and not target.dead then
-			DamageType:get(DamageType.TEMPORAL).projector(self, target.x, target.y, DamageType.TEMPORAL, dam, tmp)
-		end
-	end
-	if hitted and self:knowTalent(self.T_IMPACT) and self:isTalentActive(self.T_IMPACT) then
-		local dam = self:callTalent(self.T_IMPACT, "getDamage")
-		local power = self:callTalent(self.T_IMPACT, "getApplyPower")
-		if self:knowTalent(self.T_FRAYED_THREADS) then
-			local burst_damage = dam * self:callTalent(self.T_FRAYED_THREADS, "getPercent")
-			local burst_radius = self:callTalent(self.T_FRAYED_THREADS, "getRadius")
-			self:project({type="ball", radius=burst_radius, friendlyfire=false}, target.x, target.y, DamageType.IMPACT, {dam=burst_damage, daze=burst_damage/2, power_check=power})
-		end
-		if dam > 0 and not target.dead then
-			DamageType:get(DamageType.IMPACT).projector(self, target.x, target.y, DamageType.IMPACT, {dam=dam, daze=dam/2, power_check=power}, tmp)
-		end
-	end
-
 	if self ~= target then
 		-- Regen on being hit
 		if hitted and not target.dead and target:attr("stamina_regen_when_hit") then target:incStamina(target.stamina_regen_when_hit) end
diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua
index 82f5721415f1b9f9db7ea6189a7ea84bc659aa08..4bc37234b12796ddb70dfb4bb2e6d874e837df5f 100644
--- a/game/modules/tome/class/interface/Combat.lua
+++ b/game/modules/tome/class/interface/Combat.lua
@@ -393,6 +393,14 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 			atk = atk + effPredator.typeAttackChange
 		end
 	end
+	
+	if self:hasEffect(self.EFF_WARDEN_S_FOCUS) then
+		local eff = self:hasEffect(self.EFF_WARDEN_S_FOCUS)
+		if target == eff.target then
+			atk = atk + eff.atk
+		end
+	end
+
 
 	-- track weakness for hate bonus before the target removes it
 	local effGloomWeakness = target:hasEffect(target.EFF_GLOOM_WEAKNESS)
@@ -628,39 +636,17 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
 		end
 	end
 
-	-- Temporal cast
-	if hitted and self:knowTalent(self.T_WEAPON_FOLDING) and self:isTalentActive(self.T_WEAPON_FOLDING) then
-		local dam = self:callTalent(self.T_WEAPON_FOLDING, "getDamage")
-		local burst_damage = 0
-		local burst_radius = 0
-		if self:knowTalent(self.T_FRAYED_THREADS) then
-			local burst_damage = dam * self:callTalent(self.T_FRAYED_THREADS, "getPercent")
-			local burst_radius = self:callTalent(self.T_FRAYED_THREADS, "getRadius")
-			self:project({type="ball", radius=burst_radius, friendlyfire=false}, target.x, target.y, DamageType.TEMPORAL, burst_damage)
-		end
-		if dam > 0 and not target.dead then
-			DamageType:get(DamageType.TEMPORAL).projector(self, target.x, target.y, DamageType.TEMPORAL, dam, tmp)
-		end
-	end
-	if hitted and self:knowTalent(self.T_IMPACT) and self:isTalentActive(self.T_IMPACT) then
-		local dam = self:callTalent(self.T_IMPACT, "getDamage")
-		local power = self:callTalent(self.T_IMPACT, "getApplyPower")
-		if self:knowTalent(self.T_FRAYED_THREADS) then
-			local burst_damage = dam * self:callTalent(self.T_FRAYED_THREADS, "getPercent")
-			local burst_radius = self:callTalent(self.T_FRAYED_THREADS, "getRadius")
-			self:project({type="ball", radius=burst_radius, friendlyfire=false}, target.x, target.y, DamageType.IMPACT, {dam=burst_damage, daze=burst_damage/2, power_check=power})
-		end
-		if dam > 0 and not target.dead then
-			DamageType:get(DamageType.IMPACT).projector(self, target.x, target.y, DamageType.IMPACT, {dam=dam, daze=dam/2, power_check=power}, tmp)
-		end
-	end
-
 	-- Ruin
 	if hitted and not target.dead and self:knowTalent(self.T_RUIN) and self:isTalentActive(self.T_RUIN) then
 		local t = self:getTalentFromId(self.T_RUIN)
 		local dam = t.getDamage(self, t)
 		DamageType:get(DamageType.DRAINLIFE).projector(self, target.x, target.y, DamageType.DRAINLIFE, dam)
 	end
+	
+	-- Temporal Cast
+	if hitted and self:knowTalent(self.T_WEAPON_FOLDING) and self:isTalentActive(self.T_WEAPON_FOLDING) then
+		self:callTalent(self.T_WEAPON_FOLDING, "doWeaponFolding", target)
+	end
 
 	-- Autospell cast
 	if hitted and not target.dead and self:knowTalent(self.T_ARCANE_COMBAT) and self:isTalentActive(self.T_ARCANE_COMBAT) then
@@ -1769,6 +1755,13 @@ function _M:physicalCrit(dam, weapon, target, atk, def, add_chance, crit_power_a
 			chance = chance + p.power
 		end
 	end
+	
+	if target and self:hasEffect(self.EFF_WARDEN_S_FOCUS) then
+		local eff = self:hasEffect(self.EFF_WARDEN_S_FOCUS)
+		if target == eff.target then
+			chance = chance + eff.crit
+		end
+	end
 
 	if target then
 		chance = chance - target:combatCritReduction()
diff --git a/game/modules/tome/class/uiset/Minimalist.lua b/game/modules/tome/class/uiset/Minimalist.lua
index 25c75c9e6d98db49622fcbf47960110fe96316ea..6d8dc0802e8ce5774e1cdef4a8e9c9a84999e622 100644
--- a/game/modules/tome/class/uiset/Minimalist.lua
+++ b/game/modules/tome/class/uiset/Minimalist.lua
@@ -929,15 +929,17 @@ function _M:displayResources(scale, bx, by, a)
 				paradox_sha:setUniform("speed", 10000 - s * 7000)
 				paradox_sha.shad:use(true)
 			end
-			local p = 1 - chance / 100
+			local p = util.bound(600-player:getModifiedParadox(), 0, 300) / 300
+			--local p = 1 - chance / 100
 			shat[1]:toScreenPrecise(x+49, y+10, shat[6] * p, shat[7], 0, p * 1/shat[4], 0, 1/shat[5], paradox_c[1], paradox_c[2], paradox_c[3], a)
 			if paradox_sha.shad then paradox_sha.shad:use(false) end
 
-			if not self.res.paradox or self.res.paradox.vc ~= player.paradox or self.res.paradox.vr ~= chance then
+			local vm = player:getModifiedParadox()
+			if not self.res.paradox or self.res.paradox.vm ~= vm or self.res.paradox.vc ~= player.paradox or self.res.paradox.vr ~= chance then
 				self.res.paradox = {
 					hidable = "Paradox",
-					vc = player.paradox, vr = chance,
-					cur = {core.display.drawStringBlendedNewSurface(font_sha, ("%d"):format(player.paradox), 255, 255, 255):glTexture()},
+					vc = player.paradox, vr = chance, vm = vm,
+					cur = {core.display.drawStringBlendedNewSurface(font_sha, ("%d (%d)"):format(vm, player.paradox), 255, 255, 255):glTexture()},
 					regen={core.display.drawStringBlendedNewSurface(sfont_sha, ("%d%%"):format(chance), 255, 255, 255):glTexture()},
 				}
 			end
diff --git a/game/modules/tome/data/birth/classes/chronomancer.lua b/game/modules/tome/data/birth/classes/chronomancer.lua
index bf45189ed53b8fa596014b5d317570a1792fc33b..72ed179f61c01ddd16d637847a6ebaed837db327 100644
--- a/game/modules/tome/data/birth/classes/chronomancer.lua
+++ b/game/modules/tome/data/birth/classes/chronomancer.lua
@@ -23,7 +23,9 @@ newBirthDescriptor{
 	locked = function() return profile.mod.allow_build.chronomancer end,
 	locked_desc = "Some do not walk upon the straight road others follow. Seek the hidden paths outside the normal course of life.",
 	desc = {
-		"With one foot literally in the past and one in the future, Chronomancers manipulate the present at a whim and wield a power that only bows to nature's own need to keep the balance. The wake in spacetime they leave behind them makes their own Chronomantic abilites that much stronger and that much harder to control.  The wise Chronomancer learns to maintain the balance between his own thirst for cosmic power and the universe's need to flow undisturbed, for the hole he tears that amplifies his own abilities just may be the same hole that one day swallows him.",
+		"Exploiting a hole in the fabric of spacetime, Chronomancers learn to pull threads from other timelines into their own.",
+		"Pulling these threads creates tension and the harder they pull the more tension is produced.",
+		"Constantly they manage this tension, which they call Paradox, to avoid or control the anomalies they inevitably unleash on the world around them.",
 	},
 	descriptor_choices =
 	{
@@ -71,16 +73,17 @@ newBirthDescriptor{
 	stats = { mag=5, wil=2, con=2, },
 	talents_types = {
 		-- class
-		["chronomancy/fate-threading"]={true, 0.3},
 		["chronomancy/gravity"]={true, 0.3},
+		["chronomancy/matter"]={true, 0.3},
 		["chronomancy/spacetime-folding"]={true, 0.3},
 		["chronomancy/speed-control"]={true, 0.3},
-		["chronomancy/timeline-threading"]={true, 0.3},
 		["chronomancy/timetravel"]={true, 0.3},
 		
 		-- locked class
+		["chronomancy/flux"]={false, 0.3},
 		["chronomancy/spellbinding"]={false, 0.3},
-		["chronomancy/spatial-tears"]={false, 0.3},
+		["chronomancy/stasis"]={false, 0.3},
+		["chronomancy/timeline-threading"]={false, 0.3},
 
 		-- generic
 		["chronomancy/chronomancy"]={true, 0.3},
@@ -94,8 +97,8 @@ newBirthDescriptor{
 	talents = {
 		[ActorTalents.T_TEMPORAL_BOLT] = 1,
 		[ActorTalents.T_DIMENSIONAL_STEP] = 1,
-		[ActorTalents.T_RETHREAD] = 1,
-		[ActorTalents.T_DISENTANGLE] = 1,
+		[ActorTalents.T_REPULSION_BLAST] = 1,
+		[ActorTalents.T_PRECOGNITION] = 1,
 	},
 	copy = {
 		max_life = 90,
@@ -112,8 +115,8 @@ newBirthDescriptor{
 	locked = function() return profile.mod.allow_build.chronomancer_temporal_warden end,
 	locked_desc = "We preserve the past to protect the future. The hands of time are guarded by the arms of war.",
 	desc = {
-		"The Temporal Wardens have learned to blend archery, dual-weapon fighting, and chronomancy into a fearsome whole.",
-		"Their study of chronomancy enables them to amplify their own physical and magical abilities, and to manipulate the speed of themselves and those around them.",
+		"Their lifelines braided, Temporal Wardens have learned to work with their other selves across multiple timelines.",
+		"Through their study of chronomancy, they learn to blend archery and duel-weapon fighting, seemlessly switching from one to the other.",
 		"Their most important stats are: Magic, Dexterity, Constitution, and Willpower",
 		"#GOLD#Stat modifiers:",
 		"#LIGHT_BLUE# * +0 Strength, +2 Dexterity, +2 Constitution",
@@ -127,24 +130,23 @@ newBirthDescriptor{
 		-- class
 		["chronomancy/blade-threading"]={true, 0.3},
 		["chronomancy/bow-threading"]={true, 0.3},
-		["chronomancy/fate-threading"]={true, 0.1},
+		["chronomancy/guardian"]={true, 0.3},
 		["chronomancy/spacetime-folding"]={true, 0.3},
 		["chronomancy/speed-control"]={true, 0.3},
-		["chronomancy/guardian"]={true, 0.3},
+		["chronomancy/temporal-combat"]={true, 0.3},
 		
 		-- class locked
+		["chronomancy/stasis"]={false, 0.1},
 		["chronomancy/threaded-combat"]={false, 0.3},
 		["chronomancy/temporal-hounds"]={false, 0.3},
-		["chronomancy/timetravel"]={false, 0.1},
 		
 		-- generic
 		["technique/combat-training"]={true, 0.3},
-		
-		["chronomancy/chronomancy"]={true, 0.3},
+		["chronomancy/fate-weaving"]={true, 0.3},
 		["chronomancy/spacetime-weaving"]={true, 0.3},
 		
 		-- generic locked
-		["chronomancy/fate-weaving"]={false, 0.1},
+		["chronomancy/chronomancy"]={false, 0.1},
 		["cunning/survival"]={false, 0},
 	},
 	birth_example_particles = "temporal_focus",
@@ -153,7 +155,7 @@ newBirthDescriptor{
 		[ActorTalents.T_WEAPON_COMBAT] = 1,
 		
 		[ActorTalents.T_WARP_BLADE] = 1,
-		[ActorTalents.T_IMPACT] = 1,
+		[ActorTalents.T_THREADED_ARROW] = 1,
 		[ActorTalents.T_DIMENSIONAL_STEP] = 1,
 		[ActorTalents.T_STRENGTH_OF_PURPOSE] = 1,
 	},
@@ -162,7 +164,7 @@ newBirthDescriptor{
 		resolvers.equipbirth{ id=true,
 			{type="weapon", subtype="longbow", name="elm longbow", autoreq=true, ego_chance=-1000},
 			{type="ammo", subtype="arrow", name="quiver of elm arrows", autoreq=true, ego_chance=-1000},
-			{type="armor", subtype="light", name="rough leather armour", autoreq=true, ego_chance=-1000},
+			{type="armor", subtype="cloth", name="linen robe", autoreq=true, ego_chance=-1000},
 		},
 		resolvers.inventorybirth{ id=true, inven="QS_MAINHAND",
 			{type="weapon", subtype="longsword", name="iron longsword", autoreq=true, ego_chance=-1000},
diff --git a/game/modules/tome/data/chats/chronomancy-bias-weave.lua b/game/modules/tome/data/chats/chronomancy-bias-weave.lua
index 2d6d44881ee30288063f5203957d65c51635da98..eab7632f67a496cc255171bcc61965767eccebcd 100644
--- a/game/modules/tome/data/chats/chronomancy-bias-weave.lua
+++ b/game/modules/tome/data/chats/chronomancy-bias-weave.lua
@@ -18,7 +18,7 @@
 -- darkgod@te4.org
 
 local src = version
-local chance = src:knowTalent(src.T_BIAS_WEAVE) and src:callTalent(src.T_BIAS_WEAVE, "getBiasChance") or 0
+local chance = src:knowTalent(src.T_FLUX_CONTROL) and src:callTalent(src.T_FLUX_CONTROL, "getBiasChance") or 0
 
 local function set_bias(which)
 	src.anomaly_bias = {}
@@ -35,10 +35,10 @@ newChat{ id="welcome",
 			return set_bias({type = "physical", chance=chance}) 
 			end,
 		},
-		{"Teleport", 
+		{"Warp", 
 			action = function() 
 				game.level.map:particleEmitter(game.player.x, game.player.y, 1, "temporal_teleport")
-			return set_bias({type = "teleport", chance=chance})
+			return set_bias({type = "Warp", chance=chance})
 			end,
 		},
 		{"Temporal",
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index 58b78abfda3e74eaa6ebc88bacd90da50fa8a9fe..5b8366eac07c6a6c1b56a293dda9bfce4da13c71 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -221,7 +221,7 @@ setDefaultProjector(function(src, x, y, type, dam, state)
 			inc = inc + target:attr("inc_necrotic_minions")
 			print("[PROJECTOR] after necrotic increase dam", dam + (dam * inc) / 100)
 		end
-
+		
 		-- dark vision increases damage done in creeping dark
 		if src and src ~= target and game.level.map:checkAllEntities(x, y, "creepingDark") then
 			local dark = game.level.map:checkAllEntities(x, y, "creepingDark")
@@ -234,7 +234,6 @@ setDefaultProjector(function(src, x, y, type, dam, state)
 
 		dam = dam + (dam * inc / 100)
 
-
 		-- Blast the iceblock
 		if src.attr and src:attr("encased_in_ice") then
 			local eff = src:hasEffect(src.EFF_FROZEN)
@@ -362,10 +361,6 @@ setDefaultProjector(function(src, x, y, type, dam, state)
 			print("[PROJECTOR] after Roll With It dam", dam)
 		end
 
-		if src and src.hasEffect and src:hasEffect(src.EFF_SEAL_FATE) then
-			src:callEffect(src.EFF_SEAL_FATE, "doDamage", target)
-		end
-
 		if target:attr("resist_unseen") and not target:canSee(src) then
 			dam = dam * (1 - math.min(target.resist_unseen,100)/100)
 		end
@@ -654,6 +649,18 @@ newDamageType{
 
 newDamageType{
 	name = "physical", type = "PHYSICAL",
+	projector = function(src, x, y, type, dam, state)
+		state = state or {}
+		useImplicitCrit(src, state)
+		local realdam = DamageType.defaultProjector(src, x, y, type, dam, state)
+		
+		local target = game.level.map(x, y, Map.ACTOR)
+		if target and src.isTalentActive and src:isTalentActive(src.T_DISINTEGRATION) then
+			src:callTalent(src.T_DISINTEGRATION, "doStrip", target, type)
+		end
+		
+		return realdam
+	end,
 	death_message = {"battered", "bludgeoned", "sliced", "maimed", "raked", "bled", "impaled", "dissected", "disembowelled", "decapitated", "stabbed", "pierced", "torn limb from limb", "crushed", "shattered", "smashed", "cleaved", "swiped", "struck", "mutilated", "tortured", "skewered", "squished", "mauled", "chopped into tiny pieces", "splattered", "ground", "minced", "punctured", "hacked apart", "eviscerated"},
 }
 
@@ -858,6 +865,18 @@ newDamageType{
 newDamageType{
 	name = "temporal", type = "TEMPORAL", text_color = "#LIGHT_STEEL_BLUE#",
 	antimagic_resolve = true,
+	projector = function(src, x, y, type, dam, state)
+		state = state or {}
+		useImplicitCrit(src, state)
+		local realdam = DamageType.defaultProjector(src, x, y, type, dam, state)
+		
+		local target = game.level.map(x, y, Map.ACTOR)
+		if target and src.isTalentActive and src:isTalentActive(src.T_DISINTEGRATION) then
+			src:callTalent(src.T_DISINTEGRATION, "doStrip", target, type)
+		end
+		
+		return realdam
+	end,
 	death_message = {"timewarped", "temporally distorted", "spaghettified across the whole of space and time", "paradoxed", "replaced by a time clone (and no one ever knew the difference)", "grandfathered", "time dilated"},
 }
 
@@ -2633,7 +2652,7 @@ newDamageType{
 
 -- Temporal/Physical damage
 newDamageType{
-	name = "temporal shear", type = "MATTER",
+	name = "warp", type = "WARP",
 	projector = function(src, x, y, type, dam, state)
 		state = state or {}
 		useImplicitCrit(src, state)
@@ -2665,10 +2684,7 @@ newDamageType{
 		if target then
 			if target:isTalentActive(target.T_GRAVITY_LOCUS) then return end
 			if dam.slow then
-				target:setEffect(target.EFF_GRAVITY_SLOW, dam.dur, {dam.slow, apply_power=apply, no_ct_effect=true})
-			end
-			if dam.anti then
-				target:setEffect(target.EFF_ANTI_GRAVITY, dam.dur, {apply_power=apply, no_ct_effect=true})
+				target:setEffect(target.EFF_SLOW, dam.dur, {power=dam.slow, apply_power=apply, no_ct_effect=true})
 			end
 		end
 		DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state)
@@ -3618,10 +3634,12 @@ newDamageType{
 		if _G.type(dam) == "number" then dam = {dam=dam, apply_power=apply_power or src:combatSpellpower()} end
 		local target = game.level.map(x, y, Map.ACTOR)
 		if target then
-			target:setEffect(target.EFF_DIMENSIONAL_ANCHOR, 1, {damage=dam.dam, src=src, apply_power=dam.apply_power, no_ct_effect=true})
+			target:setEffect(target.EFF_DIMENSIONAL_ANCHOR, 1, {damage=dam.dam, daze=dam.daze, src=src, apply_power=dam.apply_power, no_ct_effect=true})
 		end
 	end,
-}newDamageType{
+}
+
+newDamageType{
 	name = "brain storm", type = "BRAINSTORM",
 	projector = function(src, x, y, type, dam, state)
 		state = state or {}
@@ -3659,85 +3677,3 @@ newDamageType{
 		end
 	end,
 }
-
--- Physical damage + daze chance
-newDamageType{
-	name = "impact", type = "IMPACT",
-	projector = function(src, x, y, type, dam, state)
-		state = state or {}
-		useImplicitCrit(src, state)
-		if _G.type(dam) == "number" then dam = {dam=dam, daze=dam/2} end
-		DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state)
-		local target = game.level.map(x, y, Map.ACTOR)
-		dam.daze = math.min(25, dam.daze) -- 25% daze chance cap
-		if target and dam.daze > 0 and rng.percent(dam.daze) then
-			if target:canBe("stun") then
-				game:onTickEnd(function() target:setEffect(target.EFF_DAZED, 2, {src=src, apply_power=dam.power_check or math.max(src:combatSpellpower(), src:combatMindpower(), src:combatAttack())}) end) -- Do it at the end so we don't break our own daze
-			else
-				game.logSeen(target, "%s resists!", target.name:capitalize())
-			end
-		end
-	end,
-}
-
--- Temporal/Physical damage with possible chance to debalitate
-newDamageType{
-	name = "warp", type = "WARP",
-	projector = function(src, x, y, type, dam, state)
-		state = state or {}
-		useImplicitCrit(src, state)
-		local target = game.level.map(x, y, Map.ACTOR)
-		if not target then return end
-		if _G.type(dam) == "number" then dam = {dam=dam, chance=chance or 0, dur=dur or 3, apply_power=apply_power or src:combatSpellpower()} end
-
-		-- Factor in fractured space bonuses
-		local fracture = false
-		if src.isTalentActive and src:isTalentActive(src.T_FRACTURED_SPACE) then
-			fracture = src:isTalentActive(src.T_FRACTURED_SPACE)
-		end
-		if fracture then
-			dam.chance = math.min(100, dam.chance + (src:callTalent(src.T_FRACTURED_SPACE, "getChance")*fracture.charges))
-			dam.dam = dam.dam * (1 + (src:callTalent(src.T_FRACTURED_SPACE, "getDamage")*fracture.charges)/100)
-		end
-
-		-- Deal Damage
-		DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam / 2, state)
-		DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam.dam / 2, state)
-
-		 -- Increase fracture charges and refresh decay rate
-		 if fracture then
-			fracture.charges = math.min(6, fracture.charges + 1)
-			fracture.decay = 0
-		end
-
-		-- Pull random effect
-		if rng.percent(dam.chance) then
-			local effect = rng.range(1, 4)
-			if effect == 1 then
-				if target:canBe("stun") then
-					target:setEffect(target.EFF_STUNNED, dam.dur, {apply_power=dam.apply_power})
-				else
-					game.logSeen(target, "%s resists the stun!", target.name:capitalize())
-				end
-			elseif effect == 2 then
-				if target:canBe("blind") then
-					target:setEffect(target.EFF_BLINDED, dam.dur, {apply_power=dam.apply_power})
-				else
-					game.logSeen(target, "%s resists the blindness!", target.name:capitalize())
-				end
-			elseif effect == 3 then
-				if target:canBe("pin") then
-					target:setEffect(target.EFF_PINNED, dam.dur, {apply_power=dam.apply_power})
-				else
-					game.logSeen(target, "%s resists the pin!", target.name:capitalize())
-				end
-			elseif effect == 4 then
-				if target:canBe("confusion") then
-					target:setEffect(target.EFF_CONFUSED, dam.dur, {power=50, apply_power=dam.apply_power})
-				else
-					game.logSeen(target, "%s resists the confusion!", target.name:capitalize())
-				end
-			end
-		end
-	end,
-}
diff --git a/game/modules/tome/data/general/npcs/horror.lua b/game/modules/tome/data/general/npcs/horror.lua
index eefa17014be308d045be2144c1e890e3bf85d43b..509782e9b05be6abec51ae2f976227525f191bfc 100644
--- a/game/modules/tome/data/general/npcs/horror.lua
+++ b/game/modules/tome/data/general/npcs/horror.lua
@@ -963,7 +963,7 @@ newEntity{ base = "BASE_NPC_HORROR",
 		[Talents.T_CHARGED_SHIELD]={base=5, every=2, max=9},
 		[Talents.T_KINETIC_LEECH]={base=3, every=3, max=5},
 		--TEMPORAL
-		[Talents.T_DISENTANGLE]={base=1, every=4, max=5},
+		[Talents.T_INDUCE_ANOMALY]={base=1, every=4, max=5},
 		[Talents.T_QUANTUM_SPIKE]={base=1, every=4, max=5},
 		[Talents.T_WEAPON_FOLDING]={base=1, every=4, max=5},
 		[Talents.T_RETHREAD]={base=2, every=4, max=5},
diff --git a/game/modules/tome/data/general/npcs/spider.lua b/game/modules/tome/data/general/npcs/spider.lua
index d38dec65ba94e58f6772cb3270f046ac3c38df89..e2fd47da4475198767c48e1e7d364bd47d71552b 100644
--- a/game/modules/tome/data/general/npcs/spider.lua
+++ b/game/modules/tome/data/general/npcs/spider.lua
@@ -286,7 +286,7 @@ newEntity{ base = "BASE_NPC_SPIDER",
 		[Talents.T_SPIN_FATE]={base=5, every=6, max=8},
 		[Talents.T_SWAP]={base=5, every=6, max=8},
 		[Talents.T_RETHREAD]={base=5, every=6, max=8},
-		[Talents.T_DISENTANGLE]={base=5, every=6, max=8},
+		[Talents.T_INDUCE_ANOMALY]={base=5, every=6, max=8},
 	},
 }
 
@@ -320,7 +320,7 @@ newEntity{ base = "BASE_NPC_SPIDER",
 		[Talents.T_SWAP]={base=5, every=6, max=8},
 		[Talents.T_RETHREAD]={base=5, every=6, max=8},
 		[Talents.T_FADE_FROM_TIME]={base=5, every=6, max=8},
-		[Talents.T_DISENTANGLE]={base=5, every=6, max=8},
+		[Talents.T_INDUCE_ANOMALY]={base=5, every=6, max=8},
 	},
 }
 
@@ -375,7 +375,7 @@ newEntity{ base = "BASE_NPC_SPIDER",
 		[Talents.T_SWAP]={base=7, every=6},
 		[Talents.T_DIMENSIONAL_STEP]={base=7, every=6},
 		[Talents.T_RETHREAD]={base=7, every=6},
-		[Talents.T_DISENTANGLE]={base=7, every=6},
+		[Talents.T_INDUCE_ANOMALY]={base=7, every=6},
 
 		[Talents.T_SUMMON]=1,
 
diff --git a/game/modules/tome/data/general/objects/world-artifacts.lua b/game/modules/tome/data/general/objects/world-artifacts.lua
index bc6fdc7cb07d876071a3d051712edc291926718f..5a0579749886722c33cb7aaac43c084acf702d53 100644
--- a/game/modules/tome/data/general/objects/world-artifacts.lua
+++ b/game/modules/tome/data/general/objects/world-artifacts.lua
@@ -2640,7 +2640,7 @@ newEntity{ base = "BASE_LONGBOW",
 	rarity = 200,
 	require = { stat = { dex=18 }, },
 	cost = 20,
-	use_no_energy = true,
+	use_no_energy = "fake",
 	material_level = 1,
 	combat = {
 		range = 9,
diff --git a/game/modules/tome/data/gfx/particles/matter_beam.lua b/game/modules/tome/data/gfx/particles/matter_beam.lua
index c80c23b2ffab70a5aafd33c3b39aac234c6fa855..4039edc764153ed4ea15830353e0385f5f995fb1 100644
--- a/game/modules/tome/data/gfx/particles/matter_beam.lua
+++ b/game/modules/tome/data/gfx/particles/matter_beam.lua
@@ -42,9 +42,9 @@ return { generator = function()
 		dir = rng.percent(50) and ray.dir + math.rad(rng.range(50, 130)) or ray.dir - math.rad(rng.range(50, 130)), dirv = 0, dira = 0,
 		vel = rng.percent(30) and 1 or 0, velv = -0.1, vela = 0.01,
 
-		r = rng.range(10, 110)/255,  rv = 0, ra = 0,
-		g = rng.range(10, 50)/255,      gv = 0, ga = 0,
-		b = rng.range(20, 125)/255,      bv = 0, ba = 0,
+		r = 180/255,  rv = 0, ra = 0,
+		g = 100/255,  gv = 0, ga = 0,
+		b = 255/255,  bv = 0, ba = 0,
 		a = rng.range(25, 255)/255,   av = 0, aa = 0,
 	}
 end, },
diff --git a/game/modules/tome/data/gfx/talents/arrow_echoes.png b/game/modules/tome/data/gfx/talents/arrow_echoes.png
new file mode 100644
index 0000000000000000000000000000000000000000..be221c7a155160f761595e63b33d3272f85e1ccb
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/arrow_echoes.png differ
diff --git a/game/modules/tome/data/gfx/talents/arrow_stitching.png b/game/modules/tome/data/gfx/talents/arrow_stitching.png
index 82bbb25f3cb97ba47488fb1e929e531c52b6b58e..f647e796b52a884ebc343ba0cc6b7ccdf9776ba2 100644
Binary files a/game/modules/tome/data/gfx/talents/arrow_stitching.png and b/game/modules/tome/data/gfx/talents/arrow_stitching.png differ
diff --git a/game/modules/tome/data/gfx/talents/attenuate.png b/game/modules/tome/data/gfx/talents/attenuate.png
new file mode 100644
index 0000000000000000000000000000000000000000..6b27b6b4b2718f04cdaa71a2dc97102c8cbbb59d
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/attenuate.png differ
diff --git a/game/modules/tome/data/gfx/talents/banish.png b/game/modules/tome/data/gfx/talents/banish.png
index 4be985d8817006a5ea8d64776125fde7e5915eae..c89b78ece7d61dd00c8597a87487dbf14e64c1b1 100644
Binary files a/game/modules/tome/data/gfx/talents/banish.png and b/game/modules/tome/data/gfx/talents/banish.png differ
diff --git a/game/modules/tome/data/gfx/talents/bias_weave.png b/game/modules/tome/data/gfx/talents/bias_weave.png
deleted file mode 100644
index 0423a06043a8e2a113a8327d1760775d08850c53..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/bias_weave.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/blade_shear.png b/game/modules/tome/data/gfx/talents/blade_shear.png
new file mode 100644
index 0000000000000000000000000000000000000000..af758f7fb1b4460003679d7018ecdf8a3edef10b
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/blade_shear.png differ
diff --git a/game/modules/tome/data/gfx/talents/blended_threads.png b/game/modules/tome/data/gfx/talents/blended_threads.png
index bd401c363df3c3a91353e256bee4e2c26c73c6ce..65c170e00e76d103f28baa365d2a4999248999da 100644
Binary files a/game/modules/tome/data/gfx/talents/blended_threads.png and b/game/modules/tome/data/gfx/talents/blended_threads.png differ
diff --git a/game/modules/tome/data/gfx/talents/blink_blade.png b/game/modules/tome/data/gfx/talents/blink_blade.png
new file mode 100644
index 0000000000000000000000000000000000000000..49d54a2092261b71befc693374f46e1a93f5f829
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/blink_blade.png differ
diff --git a/game/modules/tome/data/gfx/talents/braid_lifelines.png b/game/modules/tome/data/gfx/talents/braid_lifelines.png
index f486ca16e3e626d84e44e72a91418e20e1c496e6..f91fe4885df6fbdff561b074990df1d03a3fe89d 100644
Binary files a/game/modules/tome/data/gfx/talents/braid_lifelines.png and b/game/modules/tome/data/gfx/talents/braid_lifelines.png differ
diff --git a/game/modules/tome/data/gfx/talents/braided_blade.png b/game/modules/tome/data/gfx/talents/braided_blade.png
index 9bf419d4a056bf94c8711cf93be2c989648dbc28..3286c110a0466913828d8cf38a49c7582fbfc554 100644
Binary files a/game/modules/tome/data/gfx/talents/braided_blade.png and b/game/modules/tome/data/gfx/talents/braided_blade.png differ
diff --git a/game/modules/tome/data/gfx/talents/breach.png b/game/modules/tome/data/gfx/talents/breach.png
index 325636c2b24634c6a3bc46a0755fdd98a3957979..d037a79b6d4b2d0aa11ec20535acea5fe37e5738 100644
Binary files a/game/modules/tome/data/gfx/talents/breach.png and b/game/modules/tome/data/gfx/talents/breach.png differ
diff --git a/game/modules/tome/data/gfx/talents/cease_to_exist.png b/game/modules/tome/data/gfx/talents/cease_to_exist.png
index 1b1fab471aaafecaf1e1c8117ddcaae88b13046f..53a7372429cce2a581c8808bc73cacc2feb4ccc7 100644
Binary files a/game/modules/tome/data/gfx/talents/cease_to_exist.png and b/game/modules/tome/data/gfx/talents/cease_to_exist.png differ
diff --git a/game/modules/tome/data/gfx/talents/celerity.png b/game/modules/tome/data/gfx/talents/celerity.png
index 1b85f65dd669ae92926dfbd62c6e2da036a24500..10b0a5f84a2b45c8857de4915e1b021353c1a30a 100644
Binary files a/game/modules/tome/data/gfx/talents/celerity.png and b/game/modules/tome/data/gfx/talents/celerity.png differ
diff --git a/game/modules/tome/data/gfx/talents/chrono_time_shield.png b/game/modules/tome/data/gfx/talents/chrono_time_shield.png
new file mode 100644
index 0000000000000000000000000000000000000000..23c06dcd959f292cd08de42a8136484663ca72be
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/chrono_time_shield.png differ
diff --git a/game/modules/tome/data/gfx/talents/command_blink.png b/game/modules/tome/data/gfx/talents/command_blink.png
index ffba8fd452d5282dda596eb4f58fc674a7288b78..d46fa399163722712d5827d9f13147748a2cf738 100644
Binary files a/game/modules/tome/data/gfx/talents/command_blink.png and b/game/modules/tome/data/gfx/talents/command_blink.png differ
diff --git a/game/modules/tome/data/gfx/talents/command_breathe.png b/game/modules/tome/data/gfx/talents/command_breathe.png
index b0aca0050c3ff6f3f25f8358dcef7b6f1d499e9d..8b55a1fc178e66852270fdd26307df5313ff7ffa 100644
Binary files a/game/modules/tome/data/gfx/talents/command_breathe.png and b/game/modules/tome/data/gfx/talents/command_breathe.png differ
diff --git a/game/modules/tome/data/gfx/talents/contingency.png b/game/modules/tome/data/gfx/talents/contingency.png
index a42df9b0586d3feac30b52c0616e04f089802b6a..04cbd0210d61a9688ccdaeda68d9257eacfe4d04 100644
Binary files a/game/modules/tome/data/gfx/talents/contingency.png and b/game/modules/tome/data/gfx/talents/contingency.png differ
diff --git a/game/modules/tome/data/gfx/talents/dimensional_anchor.png b/game/modules/tome/data/gfx/talents/dimensional_anchor.png
index b83df653229172b6faf094aa019d953bf785e9df..75737bf0b4dd4259e4ea99ded6675ef88e39f4de 100644
Binary files a/game/modules/tome/data/gfx/talents/dimensional_anchor.png and b/game/modules/tome/data/gfx/talents/dimensional_anchor.png differ
diff --git a/game/modules/tome/data/gfx/talents/dimensional_shift.png b/game/modules/tome/data/gfx/talents/dimensional_shift.png
index a3a3f2e3c7c839615c3f9f7f1d0b0dfae7ba0972..42a684ea0ad7a474e73e7eb6b136d0b2bfd87d66 100644
Binary files a/game/modules/tome/data/gfx/talents/dimensional_shift.png and b/game/modules/tome/data/gfx/talents/dimensional_shift.png differ
diff --git a/game/modules/tome/data/gfx/talents/dimensional_step.png b/game/modules/tome/data/gfx/talents/dimensional_step.png
index 203657d98d94d531379bd4934b481341099833db..790d493b16fe0ab3b1865465d4044c5d7c97f9b1 100644
Binary files a/game/modules/tome/data/gfx/talents/dimensional_step.png and b/game/modules/tome/data/gfx/talents/dimensional_step.png differ
diff --git a/game/modules/tome/data/gfx/talents/disentangle.png b/game/modules/tome/data/gfx/talents/disentangle.png
deleted file mode 100644
index f0e3f6269acdacaeea168be90f7d0031342f2118..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/disentangle.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/disintegration.png b/game/modules/tome/data/gfx/talents/disintegration.png
new file mode 100644
index 0000000000000000000000000000000000000000..92540bc998169797acfd17cfea7ec87f14251ccc
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/disintegration.png differ
diff --git a/game/modules/tome/data/gfx/talents/dust_to_dust.png b/game/modules/tome/data/gfx/talents/dust_to_dust.png
index 8defd34823f12661546dfe43d1d157c72c4cfd5d..92d39be719ee04fd66f2f5501887591d4d58858a 100644
Binary files a/game/modules/tome/data/gfx/talents/dust_to_dust.png and b/game/modules/tome/data/gfx/talents/dust_to_dust.png differ
diff --git a/game/modules/tome/data/gfx/talents/echoes_from_the_past.png b/game/modules/tome/data/gfx/talents/echoes_from_the_past.png
index 1370f0481a851736ab4e959263113504aee5ca0d..cf0a1816cce9269b93580092870eebf23358dda2 100644
Binary files a/game/modules/tome/data/gfx/talents/echoes_from_the_past.png and b/game/modules/tome/data/gfx/talents/echoes_from_the_past.png differ
diff --git a/game/modules/tome/data/gfx/talents/energy_absorption.png b/game/modules/tome/data/gfx/talents/energy_absorption.png
index aaea4e17c21152f433d3f1bffaeedbb38883e14b..ae3d5b62a6ff5ca754b0bcba9203482c47c869a9 100644
Binary files a/game/modules/tome/data/gfx/talents/energy_absorption.png and b/game/modules/tome/data/gfx/talents/energy_absorption.png differ
diff --git a/game/modules/tome/data/gfx/talents/energy_decomposition.png b/game/modules/tome/data/gfx/talents/energy_decomposition.png
index b480066e721148758d7c336b47f363da2662ed94..ab039d422eafac68a1ec7b83127b65e123528060 100644
Binary files a/game/modules/tome/data/gfx/talents/energy_decomposition.png and b/game/modules/tome/data/gfx/talents/energy_decomposition.png differ
diff --git a/game/modules/tome/data/gfx/talents/entropy.png b/game/modules/tome/data/gfx/talents/entropy.png
index af9afe0b78ff555944d648432ed5ab1a3aa50c1d..a915a8d1b1de7e88965bebdce52ab1af1e0c8161 100644
Binary files a/game/modules/tome/data/gfx/talents/entropy.png and b/game/modules/tome/data/gfx/talents/entropy.png differ
diff --git a/game/modules/tome/data/gfx/talents/fateweaver.png b/game/modules/tome/data/gfx/talents/fateweaver.png
index c1cfbed29aecde24d08b39080affdf321e8a7151..9a85516bcfe0310da9ab814037e4fcf0b1a35d8b 100644
Binary files a/game/modules/tome/data/gfx/talents/fateweaver.png and b/game/modules/tome/data/gfx/talents/fateweaver.png differ
diff --git a/game/modules/tome/data/gfx/talents/fold_fate.png b/game/modules/tome/data/gfx/talents/fold_fate.png
new file mode 100644
index 0000000000000000000000000000000000000000..1200448eb15cc1b6e6b3e5036586d9c9c47315f8
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/fold_fate.png differ
diff --git a/game/modules/tome/data/gfx/talents/fold_gravity.png b/game/modules/tome/data/gfx/talents/fold_gravity.png
new file mode 100644
index 0000000000000000000000000000000000000000..2e50334a7b61698c966b71d897d85cf7e35a4e12
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/fold_gravity.png differ
diff --git a/game/modules/tome/data/gfx/talents/fold_warp.png b/game/modules/tome/data/gfx/talents/fold_warp.png
new file mode 100644
index 0000000000000000000000000000000000000000..9f347be801de318b388d3b9589890fe02d3ab193
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/fold_warp.png differ
diff --git a/game/modules/tome/data/gfx/talents/foresight.png b/game/modules/tome/data/gfx/talents/foresight.png
index 60db264019a6a862539ba1bbd1112d92c68e90ad..f3182584df262ed18a109e4c4709d77c2e17d694 100644
Binary files a/game/modules/tome/data/gfx/talents/foresight.png and b/game/modules/tome/data/gfx/talents/foresight.png differ
diff --git a/game/modules/tome/data/gfx/talents/gravity_locus.png b/game/modules/tome/data/gfx/talents/gravity_locus.png
index 1ed4b10b269de270ef08a98e8f763a868ec5e4a1..9d19e286f31e92af50dd85746a9fd6a64e2d536d 100644
Binary files a/game/modules/tome/data/gfx/talents/gravity_locus.png and b/game/modules/tome/data/gfx/talents/gravity_locus.png differ
diff --git a/game/modules/tome/data/gfx/talents/gravity_spike.png b/game/modules/tome/data/gfx/talents/gravity_spike.png
index 8a6e7b09c4f6775e3db14ebe6477b48eef8bd418..93a51414272dc1d6b2cda2cb59f62076ec012d38 100644
Binary files a/game/modules/tome/data/gfx/talents/gravity_spike.png and b/game/modules/tome/data/gfx/talents/gravity_spike.png differ
diff --git a/game/modules/tome/data/gfx/talents/gravity_well.png b/game/modules/tome/data/gfx/talents/gravity_well.png
index 4dd85288e0ef465cb65692269174294077a3f634..cf55eab961a6eeed33e8841f10e0e633b041c60d 100644
Binary files a/game/modules/tome/data/gfx/talents/gravity_well.png and b/game/modules/tome/data/gfx/talents/gravity_well.png differ
diff --git a/game/modules/tome/data/gfx/talents/guardian_unity.png b/game/modules/tome/data/gfx/talents/guardian_unity.png
index de191d5287ad656776b900860898337ed1fdbe49..3f563fce75474ced6387fdd5b0f670fb3d97d2ba 100644
Binary files a/game/modules/tome/data/gfx/talents/guardian_unity.png and b/game/modules/tome/data/gfx/talents/guardian_unity.png differ
diff --git a/game/modules/tome/data/gfx/talents/haste.png b/game/modules/tome/data/gfx/talents/haste.png
index 3ad0c5cf6d1d12aae6d3dc0dc94e5489f0520783..6e32ece1ed7f9dde022dc4d4c1204bbc55b84723 100644
Binary files a/game/modules/tome/data/gfx/talents/haste.png and b/game/modules/tome/data/gfx/talents/haste.png differ
diff --git a/game/modules/tome/data/gfx/talents/impact.png b/game/modules/tome/data/gfx/talents/impact.png
deleted file mode 100644
index f5c9e5042c1b4c93dbaff2675903f4e3513f29c4..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/impact.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/induce_anomaly.png b/game/modules/tome/data/gfx/talents/induce_anomaly.png
new file mode 100644
index 0000000000000000000000000000000000000000..e5e31586cb54eea561ba486683a5ed19e60930c9
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/induce_anomaly.png differ
diff --git a/game/modules/tome/data/gfx/talents/invigorate.png b/game/modules/tome/data/gfx/talents/invigorate.png
index 2f9c8a748bc4ed38e6862e5f142b00c2576a1d98..64f8cdc1c6b2e913ff1d2d32e7becb75c8e51893 100644
Binary files a/game/modules/tome/data/gfx/talents/invigorate.png and b/game/modules/tome/data/gfx/talents/invigorate.png differ
diff --git a/game/modules/tome/data/gfx/talents/materialize_barrier.png b/game/modules/tome/data/gfx/talents/materialize_barrier.png
new file mode 100644
index 0000000000000000000000000000000000000000..0ff7af5659566240193fe22df091ecae83636a6e
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/materialize_barrier.png differ
diff --git a/game/modules/tome/data/gfx/talents/matter_weaving.png b/game/modules/tome/data/gfx/talents/matter_weaving.png
new file mode 100644
index 0000000000000000000000000000000000000000..607a351d4be838675e9ec7ae500cf55783dbe9b8
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/matter_weaving.png differ
diff --git a/game/modules/tome/data/gfx/talents/phase_pulse.png b/game/modules/tome/data/gfx/talents/phase_pulse.png
index 0085e5161bdfadff2a626634e166e143b39aec69..7f5c7c482e37ca8015640dfcf0bfb81722e7c4fd 100644
Binary files a/game/modules/tome/data/gfx/talents/phase_pulse.png and b/game/modules/tome/data/gfx/talents/phase_pulse.png differ
diff --git a/game/modules/tome/data/gfx/talents/precognition.png b/game/modules/tome/data/gfx/talents/precognition.png
index 36d2aeff2b5e7844a73639baabe96bfb67928919..eb6d91ef54cc6d7f12942d7ab107049003b4f854 100644
Binary files a/game/modules/tome/data/gfx/talents/precognition.png and b/game/modules/tome/data/gfx/talents/precognition.png differ
diff --git a/game/modules/tome/data/gfx/talents/preserve_pattern.png b/game/modules/tome/data/gfx/talents/preserve_pattern.png
deleted file mode 100644
index df04886c58191509e2bca690f1385080f08738b0..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/preserve_pattern.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/reality_smearing.png b/game/modules/tome/data/gfx/talents/reality_smearing.png
new file mode 100644
index 0000000000000000000000000000000000000000..6b3dc3673c21b17ab10961ed4a1af47e133ea7aa
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/reality_smearing.png differ
diff --git a/game/modules/tome/data/gfx/talents/redux.png b/game/modules/tome/data/gfx/talents/redux.png
index 7ae45948d9b28d77854f9e485bf68e56b17f120f..7e998d20fb1b9bd923c96d7ef9726e8330514121 100644
Binary files a/game/modules/tome/data/gfx/talents/redux.png and b/game/modules/tome/data/gfx/talents/redux.png differ
diff --git a/game/modules/tome/data/gfx/talents/repulsion_blast.png b/game/modules/tome/data/gfx/talents/repulsion_blast.png
index 5556b8f7fbeaa5e3c44dda9e95bac04897aa22f9..ffa706eed64e32c97b3e9197813050c6296275eb 100644
Binary files a/game/modules/tome/data/gfx/talents/repulsion_blast.png and b/game/modules/tome/data/gfx/talents/repulsion_blast.png differ
diff --git a/game/modules/tome/data/gfx/talents/rethread.png b/game/modules/tome/data/gfx/talents/rethread.png
index 41fdca00a7bd57c5503239ff36ed4ca17a3a6142..3ab6b16e7a566708ddbcc81cb886807e40bc9e15 100644
Binary files a/game/modules/tome/data/gfx/talents/rethread.png and b/game/modules/tome/data/gfx/talents/rethread.png differ
diff --git a/game/modules/tome/data/gfx/talents/seal_fate.png b/game/modules/tome/data/gfx/talents/seal_fate.png
index 3258ceabba00e268e241d538d6401b89051b000e..51382646aebbd2d234a474497f725f578747a4de 100644
Binary files a/game/modules/tome/data/gfx/talents/seal_fate.png and b/game/modules/tome/data/gfx/talents/seal_fate.png differ
diff --git a/game/modules/tome/data/gfx/talents/see_the_threads.png b/game/modules/tome/data/gfx/talents/see_the_threads.png
index aa23d401ebdf7de9ffc676c7e549728795cb55ac..0ff7a0bab718b26ca22c053759f6d2013a646290 100644
Binary files a/game/modules/tome/data/gfx/talents/see_the_threads.png and b/game/modules/tome/data/gfx/talents/see_the_threads.png differ
diff --git a/game/modules/tome/data/gfx/talents/singularity_arrow.png b/game/modules/tome/data/gfx/talents/singularity_arrow.png
index c798e10a5384ce39a201028c6231ae223f606517..9f37c1cfd5396ad2707a290691d5900438ff95a1 100644
Binary files a/game/modules/tome/data/gfx/talents/singularity_arrow.png and b/game/modules/tome/data/gfx/talents/singularity_arrow.png differ
diff --git a/game/modules/tome/data/gfx/talents/spacetime_stability.png b/game/modules/tome/data/gfx/talents/spacetime_stability.png
new file mode 100644
index 0000000000000000000000000000000000000000..9344b57117450b6646eab6a4729d83fa120aef7c
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/spacetime_stability.png differ
diff --git a/game/modules/tome/data/gfx/talents/spatial_tether.png b/game/modules/tome/data/gfx/talents/spatial_tether.png
index a7144cefc368706fb9e0addedaa8d4f94bff6f99..2580dc485e300c2d491d5ddc352fc78d5cb32a6c 100644
Binary files a/game/modules/tome/data/gfx/talents/spatial_tether.png and b/game/modules/tome/data/gfx/talents/spatial_tether.png differ
diff --git a/game/modules/tome/data/gfx/talents/spin_fate.png b/game/modules/tome/data/gfx/talents/spin_fate.png
index 9fb6a19b51833415c41aebf3e5c8d2a2031c309d..3b1930beeb6b5cb2351f5bdbe034ba02e2344728 100644
Binary files a/game/modules/tome/data/gfx/talents/spin_fate.png and b/game/modules/tome/data/gfx/talents/spin_fate.png differ
diff --git a/game/modules/tome/data/gfx/talents/static_history.png b/game/modules/tome/data/gfx/talents/static_history.png
index dd5c477ff6de45c7abec14b32dd91aa2ac25789a..6299afa6976748d78efa8776147fe5128c8bb41f 100644
Binary files a/game/modules/tome/data/gfx/talents/static_history.png and b/game/modules/tome/data/gfx/talents/static_history.png differ
diff --git a/game/modules/tome/data/gfx/talents/stop.png b/game/modules/tome/data/gfx/talents/stop.png
index cce47aab99ff1ca33f2616bfa9eeeebd07896e6d..f0f71e59a0e195060777154a32d3b80567d5fd54 100644
Binary files a/game/modules/tome/data/gfx/talents/stop.png and b/game/modules/tome/data/gfx/talents/stop.png differ
diff --git a/game/modules/tome/data/gfx/talents/strength_of_purpose.png b/game/modules/tome/data/gfx/talents/strength_of_purpose.png
index 6503d241276c1c1b2c58c0ed199706127a9355f6..8d5a68aca21997bfc13a7812d40e62c37e8c259d 100644
Binary files a/game/modules/tome/data/gfx/talents/strength_of_purpose.png and b/game/modules/tome/data/gfx/talents/strength_of_purpose.png differ
diff --git a/game/modules/tome/data/gfx/talents/temporal_assault.png b/game/modules/tome/data/gfx/talents/temporal_assault.png
deleted file mode 100644
index 9b65b7086f04e6e3af6e880bd17fcf4ca9c5798c..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/temporal_assault.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/temporal_bolt.png b/game/modules/tome/data/gfx/talents/temporal_bolt.png
index f4bb163da34d6b9213ddd8959484c53f2ab5266b..58295bc5524626e11eb289b2c085fe6e6535ca30 100644
Binary files a/game/modules/tome/data/gfx/talents/temporal_bolt.png and b/game/modules/tome/data/gfx/talents/temporal_bolt.png differ
diff --git a/game/modules/tome/data/gfx/talents/temporal_fugue.png b/game/modules/tome/data/gfx/talents/temporal_fugue.png
index 2f0a4d4680122ab2dd6267cc5e1f95fd82b39d80..8ca36cee43102f1a41ee6a1d958c5b93e9c76a50 100644
Binary files a/game/modules/tome/data/gfx/talents/temporal_fugue.png and b/game/modules/tome/data/gfx/talents/temporal_fugue.png differ
diff --git a/game/modules/tome/data/gfx/talents/temporal_hounds.png b/game/modules/tome/data/gfx/talents/temporal_hounds.png
index 3e06b81397033c9141ce5a975ec1e48e5c9f919c..ee9ebc62058a6498d7b224730c9e352cbde886e0 100644
Binary files a/game/modules/tome/data/gfx/talents/temporal_hounds.png and b/game/modules/tome/data/gfx/talents/temporal_hounds.png differ
diff --git a/game/modules/tome/data/gfx/talents/temporal_reprieve.png b/game/modules/tome/data/gfx/talents/temporal_reprieve.png
index b31b9f88e35c13e70bade128ecaa75aa452405a4..b77dffbca08f5c78fe50dc335c8165a5fe027620 100644
Binary files a/game/modules/tome/data/gfx/talents/temporal_reprieve.png and b/game/modules/tome/data/gfx/talents/temporal_reprieve.png differ
diff --git a/game/modules/tome/data/gfx/talents/temporal_vigour.png b/game/modules/tome/data/gfx/talents/temporal_vigour.png
index d75910100f7eb4c7247840f810424aa839faaff8..dc71455da415d22a61346dd2190fe1b9f75239a7 100644
Binary files a/game/modules/tome/data/gfx/talents/temporal_vigour.png and b/game/modules/tome/data/gfx/talents/temporal_vigour.png differ
diff --git a/game/modules/tome/data/gfx/talents/thread_the_needle.png b/game/modules/tome/data/gfx/talents/thread_the_needle.png
index 8a5cd84599fccbe546536e361d456d649dfcc59a..a775ddb4945286e609c682d34a01a21689145e60 100644
Binary files a/game/modules/tome/data/gfx/talents/thread_the_needle.png and b/game/modules/tome/data/gfx/talents/thread_the_needle.png differ
diff --git a/game/modules/tome/data/gfx/talents/thread_walk.png b/game/modules/tome/data/gfx/talents/thread_walk.png
new file mode 100644
index 0000000000000000000000000000000000000000..6455180b333d44ed12b83f265a99a5b65332efc3
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/thread_walk.png differ
diff --git a/game/modules/tome/data/gfx/talents/threaded_arrow.png b/game/modules/tome/data/gfx/talents/threaded_arrow.png
index dc88dafce4502d6d50b74e20fe115667340796dd..089e35ea9245e9126515e300ef8c28144dc0d28e 100644
Binary files a/game/modules/tome/data/gfx/talents/threaded_arrow.png and b/game/modules/tome/data/gfx/talents/threaded_arrow.png differ
diff --git a/game/modules/tome/data/gfx/talents/time_dilation.png b/game/modules/tome/data/gfx/talents/time_dilation.png
index 9d26c4d4f3b1662e3cc1d6a648eb378b766bf4c4..ad3a30faf9c5843cdd1e50ae92dec6af1ce13ba5 100644
Binary files a/game/modules/tome/data/gfx/talents/time_dilation.png and b/game/modules/tome/data/gfx/talents/time_dilation.png differ
diff --git a/game/modules/tome/data/gfx/talents/time_skip.png b/game/modules/tome/data/gfx/talents/time_skip.png
index 5b59b98746d469aa7dcd7d667ea8304ab4b92ac7..379a094690c2fcc3780f65cf58a861923157485a 100644
Binary files a/game/modules/tome/data/gfx/talents/time_skip.png and b/game/modules/tome/data/gfx/talents/time_skip.png differ
diff --git a/game/modules/tome/data/gfx/talents/time_stop.png b/game/modules/tome/data/gfx/talents/time_stop.png
index e535f4e28b3240d7fddadcac523f8331c7cc9227..fd0147acd0100450e0c8c4a85e1ee04da337c4c2 100644
Binary files a/game/modules/tome/data/gfx/talents/time_stop.png and b/game/modules/tome/data/gfx/talents/time_stop.png differ
diff --git a/game/modules/tome/data/gfx/talents/trim_threads.png b/game/modules/tome/data/gfx/talents/trim_threads.png
deleted file mode 100644
index 438efab681d07c657139636727cadd4f7e0ff687..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/trim_threads.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/twin_threads.png b/game/modules/tome/data/gfx/talents/twin_threads.png
deleted file mode 100644
index 7aa012ffafb14d15e8b97805b0330f97d98136be..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/twin_threads.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/twist_fate.png b/game/modules/tome/data/gfx/talents/twist_fate.png
new file mode 100644
index 0000000000000000000000000000000000000000..59ef61da33baad416a9ef7ff0d89e56b4cb10af1
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/twist_fate.png differ
diff --git a/game/modules/tome/data/gfx/talents/vigilance.png b/game/modules/tome/data/gfx/talents/vigilance.png
new file mode 100644
index 0000000000000000000000000000000000000000..b6bd79a17bcd92899969174270fd25f5961d3c1e
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/vigilance.png differ
diff --git a/game/modules/tome/data/gfx/talents/warden_s_call.png b/game/modules/tome/data/gfx/talents/warden_s_call.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d1434a24866f39d6c2144938f09bff521478482
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/warden_s_call.png differ
diff --git a/game/modules/tome/data/gfx/talents/warden_s_focus.png b/game/modules/tome/data/gfx/talents/warden_s_focus.png
new file mode 100644
index 0000000000000000000000000000000000000000..84413e3f83d576ef5253b968742bd01f01302c4b
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/warden_s_focus.png differ
diff --git a/game/modules/tome/data/gfx/talents/wardens_call.png b/game/modules/tome/data/gfx/talents/wardens_call.png
new file mode 100644
index 0000000000000000000000000000000000000000..146356ca448e789f14afb08d2bf38979a459a6ed
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/wardens_call.png differ
diff --git a/game/modules/tome/data/gfx/talents/warp.png b/game/modules/tome/data/gfx/talents/warp.png
deleted file mode 100644
index 470815ea4e452f4ab4197c0d996929ce2fd7af9c..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/warp.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/warp_blade.png b/game/modules/tome/data/gfx/talents/warp_blade.png
index 67fcda3f4804b1dcc8c82842c13584cfb671581f..82e4189fc695f0f1654586c47b379020ead3bb19 100644
Binary files a/game/modules/tome/data/gfx/talents/warp_blade.png and b/game/modules/tome/data/gfx/talents/warp_blade.png differ
diff --git a/game/modules/tome/data/gfx/talents/warp_mastery.png b/game/modules/tome/data/gfx/talents/warp_mastery.png
deleted file mode 100644
index b9a1d90c628701939b6e1930b86e38c86cb37fc7..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/gfx/talents/warp_mastery.png and /dev/null differ
diff --git a/game/modules/tome/data/gfx/talents/warp_mine_away.png b/game/modules/tome/data/gfx/talents/warp_mine_away.png
index f08f5ff1961ba9331a4847ea400bd1abef670676..7f94125057f941005a27009f282b764be0d986eb 100644
Binary files a/game/modules/tome/data/gfx/talents/warp_mine_away.png and b/game/modules/tome/data/gfx/talents/warp_mine_away.png differ
diff --git a/game/modules/tome/data/gfx/talents/warp_mine_toward.png b/game/modules/tome/data/gfx/talents/warp_mine_toward.png
index 5c509a8f16c21423284337f167508b1b2eb16d1e..75e42b2690601da26d9bed0009e75a68553a2d19 100644
Binary files a/game/modules/tome/data/gfx/talents/warp_mine_toward.png and b/game/modules/tome/data/gfx/talents/warp_mine_toward.png differ
diff --git a/game/modules/tome/data/gfx/talents/warp_mines.png b/game/modules/tome/data/gfx/talents/warp_mines.png
index 31d9e2210e3a8237a70b26417676a82532f643a6..2774567f4da98ba6886651b0a8cac1310bbd18ed 100644
Binary files a/game/modules/tome/data/gfx/talents/warp_mines.png and b/game/modules/tome/data/gfx/talents/warp_mines.png differ
diff --git a/game/modules/tome/data/gfx/talents/weapon_folding.png b/game/modules/tome/data/gfx/talents/weapon_folding.png
index 535925f75a07786c2786e29dce8acfdb4bb56472..0d6443cbc98e7b2b04d2408a9120c68b0a94a782 100644
Binary files a/game/modules/tome/data/gfx/talents/weapon_folding.png and b/game/modules/tome/data/gfx/talents/weapon_folding.png differ
diff --git a/game/modules/tome/data/gfx/talents/weapon_manifold.png b/game/modules/tome/data/gfx/talents/weapon_manifold.png
new file mode 100644
index 0000000000000000000000000000000000000000..ba80c4f2183adbf0720f429f0be60c9400a2d7d6
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/weapon_manifold.png differ
diff --git a/game/modules/tome/data/gfx/talents/webs_of_fate.png b/game/modules/tome/data/gfx/talents/webs_of_fate.png
index 71803764fa6797423c5407f345ebfc34a873f96f..2ab65c08542f266b2c1ecb39165e614b6f98327b 100644
Binary files a/game/modules/tome/data/gfx/talents/webs_of_fate.png and b/game/modules/tome/data/gfx/talents/webs_of_fate.png differ
diff --git a/game/modules/tome/data/gfx/talents/wormhole.png b/game/modules/tome/data/gfx/talents/wormhole.png
index f34fe5e73422a3183267fb223ba0587eb145e655..22f3c62e0f9c5fe4d1725e6d0f6bb44a197da13e 100644
Binary files a/game/modules/tome/data/gfx/talents/wormhole.png and b/game/modules/tome/data/gfx/talents/wormhole.png differ
diff --git a/game/modules/tome/data/quests/paradoxology.lua b/game/modules/tome/data/quests/paradoxology.lua
index 309a95720782af2588df15042328f2736cce4b83..1b4c0cb52f6010bde473468e3a1b4123cda03aa0 100644
--- a/game/modules/tome/data/quests/paradoxology.lua
+++ b/game/modules/tome/data/quests/paradoxology.lua
@@ -66,24 +66,23 @@ generate = function(self, player, x, y)
 	end
 
 	-- Add talents
-	a:learnTalent(a.T_TURN_BACK_THE_CLOCK, true, 3)
-	a:learnTalent(a.T_BODY_REVERSION, true, 3)
-	a:learnTalent(a.T_TEMPORAL_FUGUE, true, 4)
-	a:learnTalent(a.T_DISENTANGLE, true, 4)
-	a:learnTalent(a.T_RETHREAD, true, 3)
-	a:learnTalent(a.T_GATHER_THE_THREADS, true, 3)
-	a:learnTalent(a.T_FADE_FROM_TIME, true, 3)
+	a:learnTalent(a.T_TEMPORAL_BOLT, true, 3)
+	a:learnTalent(a.T_TIME_SKIP, true, 3)
+	a:learnTalent(a.T_INDUCE_ANOMALY, true, 3)
+	a:learnTalent(a.T_REALITY_SMEARING, true, 3)
 	a:learnTalent(a.T_ASHES_TO_ASHES, true, 4)
-	a:learnTalent(a.T_QUANTUM_SPIKE, true, 3)
+	a:learnTalent(a.T_DUST_TO_DUST, true, 4)
 	a:learnTalent(a.T_SEVER_LIFELINE, true, 5)
 
 	a.talent_cd_reduction = a.talent_cd_reduction or {}
-	a.talent_cd_reduction[a.T_DISENTANGLE] = 15
 	a.talents_cd[a.T_SEVER_LIFELINE] = 20
+	
+	a:forceUseTalent(a.T_REALITY_SMEARING, {ignore_energy=true})
 
 	a:forceLevelup(a.level + 7)
 
 	a:incIncStat("wil", 200)
+	a.anomaly_bias = {type = "temporal", chance=100}
 	a.self_resurrect = nil -- In case this is a skeleton player
 	a.on_die = function(self)
 		local o = game.zone:makeEntityByName(game.level, "object", "RUNE_RIFT")
diff --git a/game/modules/tome/data/talents/chronomancy/anomalies.lua b/game/modules/tome/data/talents/chronomancy/anomalies.lua
index 245edd517a59a823a9ce4fb8b42d108de6a7ed3a..19cf6215249893f2f7de8879e3c8f94e67145211 100644
--- a/game/modules/tome/data/talents/chronomancy/anomalies.lua
+++ b/game/modules/tome/data/talents/chronomancy/anomalies.lua
@@ -98,32 +98,12 @@ getAnomalyPosition = function(self, range)
 	return x, y
 end
 
--- Allows the caster to target the anomaly
--- For this to work all anomalies have to have no_energy set to true in the talent table, otherwise it will use two turns
-checkAnomalyTargeting = function(self, t, tg)
-	local x, y = self.x, self.y
-	if self:knowTalent(self.T_BIAS_WEAVE) and rng.percent(self:callTalent(self.T_BIAS_WEAVE, "getTargetChance")) and not self:attr("anomaly_forced_target") then
-		if self == game.player then
-			game.bignews:saySimple(180, "#STEEL_BLUE#Targeting %s", t.name)
-		end
-		
-		x, y = self:getTarget(tg)
-		
-		-- If the player cancels target them anyway
-		if not x or not y then
-			x, y = self.x, self.y
-		end
-	end
-	local _ _, _, _, x, y = self:canProject(tg, x, y)
-	return x, y
-end
-
 -- Check for effects when hit by an anomaly
 -- This is called before immunity is checked
 checkAnomalyTriggers = function(self, target)
-	if target:hasEffect(target.EFF_TRIM_THREADS) then
-		local eff = target:hasEffect(target.EFF_TRIM_THREADS)
-		eff.src:callTalent(eff.src.T_TRIM_THREADS, "doAnomaly", target, eff)
+	if target:hasEffect(target.EFF_ATTENUATE) then
+		local eff = target:hasEffect(target.EFF_ATTENUATE)
+		eff.src:callTalent(eff.src.T_ATTENUATE, "doAnomaly", target, eff)
 	end
 end
 
@@ -131,7 +111,7 @@ end
 newTalent{
 	name = "Anomaly Rearrange",
 	type = {"chronomancy/anomalies", 1},
-	anomaly_type = "teleport",
+	anomaly_type = "warp",
 	type_no_req = true,
 	no_unlearn_last = true,
 	points = 1,
@@ -140,7 +120,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -148,7 +127,10 @@ newTalent{
 	message = "@Source@ causes a spacetime hiccup.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
+
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		-- Randomly take targets
@@ -175,7 +157,7 @@ newTalent{
 newTalent{
 	name = "Anomaly Teleport",
 	type = {"chronomancy/anomalies", 1},
-	anomaly_type = "teleport",
+	anomaly_type = "warp",
 	type_no_req = true,
 	no_unlearn_last = true,
 	points = 1,
@@ -184,7 +166,6 @@ newTalent{
 	range = function(self, t) return getAnomalyRange(self, t) end,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=10, radius=self:getTalentRadius(t)}
@@ -192,7 +173,9 @@ newTalent{
 	message = "@Source@ shifts reality.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		-- Randomly take targets
@@ -220,7 +203,7 @@ newTalent{
 newTalent{
 	name = "Anomaly Swap",
 	type = {"chronomancy/anomalies", 1},
-	anomaly_type = "teleport",
+	anomaly_type = "warp",
 	type_no_req = true,
 	no_unlearn_last = true,
 	points = 1,
@@ -229,7 +212,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -237,7 +219,9 @@ newTalent{
 	message = "@Source@ swaps places with a nearby target.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRange(t), true)
 
 		-- Randomly take targets
@@ -275,7 +259,7 @@ newTalent{
 newTalent{
 	name = "Anomaly Displacement Shield",
 	type = {"chronomancy/anomalies", 1},
-	anomaly_type = "teleport",
+	anomaly_type = "warp",
 	type_no_req = true,
 	no_unlearn_last = true,
 	points = 1,
@@ -284,7 +268,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), nowarning=true}
@@ -292,7 +275,9 @@ newTalent{
 	message = "@Source@ transfers damage to a nearby target.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t), true)
 
 		-- Randomly take targets
@@ -320,7 +305,7 @@ newTalent{
 newTalent{
 	name = "Anomaly Wormhole",
 	type = {"chronomancy/anomalies", 1},
-	anomaly_type = "teleport",
+	anomaly_type = "warp",
 	type_no_req = true,
 	no_unlearn_last = true,
 	points = 1,
@@ -328,7 +313,6 @@ newTalent{
 	cooldown =0,
 	range = 10,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="bolt", nowarning=true, range=10, nolock=true, simple_dir_request=true, talent=t}
@@ -336,7 +320,9 @@ newTalent{
 	message = "@Source@ folds the space between two points.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		if (x == self.x and y == self.y) or game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move")then
 			x, y = getAnomalyPosition(self, self:getTalentRange(t))
 		end
@@ -412,7 +398,7 @@ newTalent{
 newTalent{
 	name = "Anomaly Probability Travel",
 	type = {"chronomancy/anomalies", 1},
-	anomaly_type = "teleport",
+	anomaly_type = "warp",
 	type_no_req = true,
 	no_unlearn_last = true,
 	points = 1,
@@ -421,7 +407,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), nowarning=true}
@@ -429,7 +414,9 @@ newTalent{
 	message = "@Source@ places several targets out of phase.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		for i = 1, rng.avg(1, 5, 3) do
@@ -455,7 +442,7 @@ newTalent{
 newTalent{
 	name = "Anomaly Blink",
 	type = {"chronomancy/anomalies", 1},
-	anomaly_type = "teleport",
+	anomaly_type = "warp",
 	type_no_req = true,
 	no_unlearn_last = true,
 	points = 1,
@@ -464,7 +451,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -472,7 +458,9 @@ newTalent{
 	message = "@Source@ makes several targets blink uncontrollably.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		for i = 1, rng.avg(1, 5, 3) do
@@ -498,7 +486,7 @@ newTalent{
 newTalent{
 	name = "Anomaly Summon Townsfolk",
 	type = {"chronomancy/anomalies", 1},
-	anomaly_type = "teleport",
+	anomaly_type = "warp",
 	type_no_req = true,
 	no_unlearn_last = true,
 	points = 1,
@@ -508,7 +496,6 @@ newTalent{
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
 	requires_target = true,
-	no_energy = true, 
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
 	end,
@@ -516,7 +503,9 @@ newTalent{
 	message = "Some innocent bystanders have been teleported into the fight.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		
 		-- Randomly pick a race
 		local race = rng.range(1, 4)
@@ -615,8 +604,7 @@ newTalent{
 	cooldown =0,
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
-	direct_hit = true,
-	no_energy = true, 
+	direct_hit = true,	
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -625,7 +613,9 @@ newTalent{
 	message = "@Source@ creates a bubble of slow time.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		for i = 1, rng.avg(1, 5, 3) do
@@ -659,8 +649,7 @@ newTalent{
 	cooldown =0,
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
-	direct_hit = true,
-	no_energy = true, 
+	direct_hit = true,	
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), nowarning=true}
@@ -669,7 +658,9 @@ newTalent{
 	message = "@Source@ creates a bubble of fast time.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		for i = 1, rng.avg(1, 5, 3) do
@@ -703,7 +694,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -711,7 +701,9 @@ newTalent{
 	message = "@Source@ creates a bubble of nul time.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		for i = 1, rng.avg(1, 5, 3) do
@@ -747,7 +739,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -755,7 +746,9 @@ newTalent{
 	message = "@Source@ removes several targets from time.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		for i = 1, rng.avg(1, 5, 3) do
@@ -791,15 +784,16 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), nowarning=true}
 	end,
-	message = "@Source@ smears several targets.",
+	message = "@Source@ creates a temporal shield around several targets.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		for i = 1, rng.avg(1, 5, 3) do
@@ -833,7 +827,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), nowarning=true}
@@ -841,7 +834,9 @@ newTalent{
 	message = "@Source@ energizes several targets.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		for i = 1, rng.avg(1, 5, 3) do
@@ -875,7 +870,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), nowarning=true}
@@ -883,7 +877,9 @@ newTalent{
 	message = "@Source@ clones a nearby creature.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		-- Randomly take targets
@@ -921,7 +917,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -929,7 +924,9 @@ newTalent{
 	message = "@Source@ creates a temporal storm.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		
 		-- Add a lasting map effect
 		game.level.map:addEffect(self,
@@ -963,7 +960,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -971,7 +967,9 @@ newTalent{
 	message = "@Source@ increases local gravity.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 
 		self:project(tg, x, y, function(px, py)
 			local target = game.level.map(px, py, Map.ACTOR)
@@ -1007,7 +1005,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1015,7 +1012,9 @@ newTalent{
 	message = "@Source@ turns matter to dust.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 
 		self:project(tg, x, y, DamageType.DIG, 1)
 		game.level.map:particleEmitter(x, y, tg.radius, "ball_earth", {radius=tg.radius})
@@ -1039,7 +1038,6 @@ newTalent{
 	range = 10,
 	radius = 1,
 	direct_hit = true,
-	no_energy = true, 
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), nowarning=true}
@@ -1047,7 +1045,9 @@ newTalent{
 	message = "@Source@ creates a stone wall.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		
 		for i = -1, 1 do for j = -1, 1 do if game.level.map:isBound(x + i, y + j) then
 			local oe = game.level.map(x + i, y + j, Map.TERRAIN)
@@ -1115,7 +1115,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1123,7 +1122,9 @@ newTalent{
 	message = "@Source@ increases local entropy.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		-- Randomly take targets
@@ -1174,15 +1175,17 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
-	requires_target = true,
+
+requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
 	end,
 	message = "@Source@ increases local gravity.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		-- Randomly take targets
@@ -1218,7 +1221,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1226,7 +1228,9 @@ newTalent{
 	message = "@Source@ causes an earthquake.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		
 		-- Don't bury the player
 		if not game.player:knowTalent(game.player.T_DIG_OBJECT) then
@@ -1254,7 +1258,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1262,7 +1265,9 @@ newTalent{
 	message = "@Source@ crumbles the resistances of several targets.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		-- Randomly take targets
@@ -1295,7 +1300,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1303,7 +1307,9 @@ newTalent{
 	message = "@Source@ causes a dust storm.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if not x or not y then x, y = self.x, self.y end
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRange(t))
 		
 		local dam = getAnomalyRadius(self, t) -- not a typo, very low damage since this isn't a major anomaly
@@ -1345,6 +1351,7 @@ newTalent{
 }
 
 -- Major
+-- Major anomalies can't be manually targeted
 newTalent{
 	name = "Anomaly Blazing Fire",
 	type = {"chronomancy/anomalies", 1},
@@ -1357,7 +1364,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1415,7 +1421,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1423,7 +1428,7 @@ newTalent{
 	message = "@Source@ calcifies several targets.",
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = checkAnomalyTargeting(self, t, tg)
+		local x, y = self:getTarget(tg)
 		local tgts = getAnomalyTargets(self, t, x, y, "ACTOR", self:getTalentRadius(t))
 
 		-- Randomly take targets
@@ -1458,7 +1463,6 @@ newTalent{
 	range = 50,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), talent=t}
@@ -1501,7 +1505,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), talent=t}
@@ -1542,7 +1545,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), talent=t}
@@ -1583,7 +1585,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), talent=t}
@@ -1630,8 +1631,8 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true, 
-	requires_target = true,
+
+requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
 	end,
@@ -1664,7 +1665,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1722,7 +1722,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1799,7 +1798,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1893,7 +1891,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
@@ -1975,7 +1972,6 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return getAnomalyRadius(self, t) end,
 	direct_hit = true,
-	no_energy = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
diff --git a/game/modules/tome/data/talents/chronomancy/blade-threading.lua b/game/modules/tome/data/talents/chronomancy/blade-threading.lua
index d1cb1904c9c345711abdc4c1b17197bb6ddba80b..e216a330634db5252a7b936ecd64ebb77e9f52cd 100644
--- a/game/modules/tome/data/talents/chronomancy/blade-threading.lua
+++ b/game/modules/tome/data/talents/chronomancy/blade-threading.lua
@@ -19,13 +19,17 @@
 
 -- EDGE TODO: Particles, Timed Effect Particles
 
+local function bow_warden(self, target)
+	if self:knowTalent(self.T_WARDEN_S_CALL) then self:callTalent(self.T_WARDEN_S_CALL, "doBowWarden", target) end
+end
+
 newTalent{
 	name = "Warp Blade",
 	type = {"chronomancy/blade-threading", 1},
 	require = chrono_req1,
 	points = 5,
 	cooldown = 6,
-	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
+	paradox = function (self, t) return getParadoxCost(self, t, 8) end,
 	tactical = { ATTACK = {weapon = 2}, DISABLE = 3 },
 	requires_target = true,
 	speed = "weapon",
@@ -33,11 +37,11 @@ newTalent{
 	is_melee = true,
 	target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
 	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
-	getWarp = function(self, t) return 7 + self:combatSpellpower(0.092) * self:combatTalentScale(t, 1, 7) end,
+	getWarp = function(self, t) return self:combatTalentSpellDamage(t, 15, 40, getParadoxSpellpower(self, t)) end,
 	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 3, 7))) end,
 	on_pre_use = function(self, t, silent) if not doWardenPreUse(self, "dual") then if not silent then game.logPlayer(self, "You require two weapons to use this talent.") end return false end return true end,
 	action = function(self, t)
-		local dam, swap = doWardenWeaponSwap(self, t, t.getDamage(self, t))
+		local swap, dam = doWardenWeaponSwap(self, t, t.getDamage(self, t), "blade")
 
 		local tg = self:getTalentTarget(t)
 		local x, y, target = self:getTarget(tg)
@@ -51,8 +55,11 @@ newTalent{
 
 		-- Project our warp
 		if hitted then
-			self:project({type="hit"}, target.x, target.y, DamageType.WARP, {dam=self:spellCrit(t.getWarp(self, t)), chance=100, dur=t.getDuration(self, t), apply_power=getParadoxSpellpower(self, t)})
+			bow_warden(self, target)
+			self:project({type="hit"}, target.x, target.y, DamageType.WARP, self:spellCrit(t.getWarp(self, t)))
+			
 			game.level.map:particleEmitter(target.x, target.y, 1, "generic_discharge", {rm=64, rM=64, gm=134, gM=134, bm=170, bM=170, am=35, aM=90})
+			randomWarpEffect(self, t, target)
 		end
 
 		return true
@@ -61,85 +68,60 @@ newTalent{
 		local damage = t.getDamage(self, t) * 100
 		local duration = t.getDuration(self, t)
 		local warp = t.getWarp(self, t)
-		return ([[Attack the target with your melee weapons for %d%%.
-		If the attack hits you'll warp the target, dealing %0.2f temporal and %0.2f physical damage, and may stun, blind, pin, or confuse them for %d turns.
-		The bonus damage improves with your Spellpower.]])
+		return ([[Attack with your melee weapons for %d%% damage.
+		If either attack hits you'll warp the target, dealing %0.2f temporal and %0.2f physical (warp) damage, and may stun, blind, pin, or confuse them for %d turns.
+		The bonus damage scales with your Spellpower.]])
 		:format(damage, damDesc(self, DamageType.TEMPORAL, warp/2), damDesc(self, DamageType.PHYSICAL, warp/2), duration)
 	end
 }
 
 newTalent{
-	name = "Weapon Folding",
+	name = "Braided Blade",
 	type = {"chronomancy/blade-threading", 2},
-	mode = "sustained",
 	require = chrono_req2,
-	sustain_paradox = 12,
-	cooldown = 10,
-	tactical = { BUFF = 2 },
-	points = 5,
-	getDamage = function(self, t) return 7 + self:combatSpellpower(0.092) * self:combatTalentScale(t, 1, 7) end,
-	activate = function(self, t)
-		return {}
-	end,
-	deactivate = function(self, t, p)
-		return true
-	end,
-	info = function(self, t)
-		local damage = t.getDamage(self, t)
-		return ([[Folds a single dimension of your weapons (or ammo) upon itself, adding %0.2f temporal damage to your strikes and  increasing your armour penetration by %d.
-		The armour penetration and damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.TEMPORAL, damage), damage/2)
-	end,
-}
-
-newTalent{
-	name = "Braided Blade",
-	type = {"chronomancy/blade-threading", 3},
-	require = chrono_req3,
 	points = 5,
 	cooldown = 8,
-	paradox = function (self, t) return getParadoxCost(self, t, 15) end,
+	paradox = function (self, t) return getParadoxCost(self, t, 12) end,
 	tactical = { ATTACKAREA = {weapon = 2}, DISABLE = 3 },
 	requires_target = true,
 	speed = "weapon",
-	range = 1,
+	range = function(self, t) return 3 + math.floor(self:combatTalentLimit(t, 7, 0, 3)) end,
 	is_melee = true,
-	target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
-	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	target = function(self, t)
+		return {type="beam", range=self:getTalentRange(t), talent=t, selffire=false }
+	end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.8, 1.3) end,
 	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 3, 7))) end,
 	getPower = function(self, t) return self:combatTalentSpellDamage(t, 50, 150, getParadoxSpellpower(self, t)) end,
 	on_pre_use = function(self, t, silent) if not doWardenPreUse(self, "dual") then if not silent then game.logPlayer(self, "You require two weapons to use this talent.") end return false end return true end,
 	action = function(self, t)
-		local dam, swap = doWardenWeaponSwap(self, t, t.getDamage(self, t))
-
+		local swap, dam = doWardenWeaponSwap(self, t, t.getDamage(self, t), "blade")
 		local tg = self:getTalentTarget(t)
-		local x, y, target = self:getTarget(tg)
-		if not target or not self:canProject(tg, x, y) then
+		local x, y = self:getTarget(tg)
+	
+		if not x or not y then
 			if swap then doWardenWeaponSwap(self, t, nil, "bow") end
 			return nil
 		end
-
+		
 		local braid_targets = {}
-
-		-- get left and right side
-		local dir = util.getDir(x, y, self.x, self.y)
-		local lx, ly = util.coordAddDir(self.x, self.y, util.dirSides(dir, self.x, self.y).left)
-		local rx, ry = util.coordAddDir(self.x, self.y, util.dirSides(dir, self.x, self.y).right)
-		local lt, rt = game.level.map(lx, ly, Map.ACTOR), game.level.map(rx, ry, Map.ACTOR)
-
-		-- target hit
-		local hit1 = self:attackTarget(target, nil, damage, true)
-		if hit1 then braid_targets[#braid_targets+1] = target end
-
-		--left hit
-		if lt and self:reactionToward(lt) < 0 then
-			local hit2 = self:attackTarget(lt, nil, damage, true)
-			if hit2 then braid_targets[#braid_targets+1] = lt end
-		end
-		--right hit
-		if rt and self:reactionToward(rt) < 0 then
-			local hit3 = self:attackTarget(rt, nil, damage, true)
-			if hit3 then braid_targets[#braid_targets+1] = rt end
-		end
+		local bow_done = false
+		
+		self:project(tg, x, y, function(px, py, tg, self)
+			local target = game.level.map(px, py, Map.ACTOR)
+			if target then
+				local hit = self:attackTarget(target, DamageType.TEMPORAL, t.getDamage(self, t), true)
+				if hit then
+					if not bow_done then
+						bow_done = true
+						bow_warden(self, target)
+					end
+					if not target.dead and self:reactionToward(target) < 0 then
+						braid_targets[#braid_targets+1] = target
+					end
+				end
+			end
+		end)
 
 		-- if we hit more than one, braid them
 		if #braid_targets > 1 then
@@ -148,27 +130,32 @@ newTalent{
 				target:setEffect(target.EFF_BRAIDED, t.getDuration(self, t), {power=t.getPower(self, t), src=self, targets=braid_targets})
 			end
 		end
-
+		
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(x-self.x), math.abs(y-self.y)), "temporalbeam", {tx=x-self.x, ty=y-self.y})
+		game:playSoundNear(self, "talents/heal")
+		
 		return true
 	end,
 	info = function(self, t)
 		local damage = t.getDamage(self, t) * 100
 		local duration = t.getDuration(self, t)
 		local power = t.getPower(self, t)
-		return ([[Attack your foes in a frontal arc, doing %d%% weapon damage.  If two or more targets are hit you'll braid their lifelines for %d turns.
+		return ([[Attack all targets in a beam with your melee weapons for %d%% temporal weapon damage.
+		If two or more targets are hit by the beam you'll braid their lifelines for %d turns.
 		Braided targets take %d%% of all damage dealt to other braided targets.
-		The damage transfered by the braid effect scales with your Spellpower.]])
+		The damage transferred by the braid effect and beam damage scales with your Spellpower.]])
 		:format(damage, duration, power)
 	end
 }
 
 newTalent{
-	name = "Temporal Assault",
-	type = {"chronomancy/blade-threading", 4},
-	require = chrono_req4,
+	name = "Blink Blade",
+	type = {"chronomancy/blade-threading", 3},
+	require = chrono_req3,
 	points = 5,
-	cooldown = 12,
-	paradox = function (self, t) return getParadoxCost(self, t, 15) end,
+	cooldown = 8,
+	paradox = function (self, t) return getParadoxCost(self, t, 12) end,
 	tactical = { ATTACKAREA = {weapon = 2}, ATTACK = {weapon = 2},  },
 	requires_target = true,
 	is_teleport = true,
@@ -176,11 +163,11 @@ newTalent{
 	range = 1,
 	is_melee = true,
 	target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
-	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.6, 1.2) end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.4, 1) end,
 	getTeleports = function(self, t) return self:getTalentLevel(t) >= 5 and 2 or 1 end,
 	on_pre_use = function(self, t, silent) if not doWardenPreUse(self, "dual") then if not silent then game.logPlayer(self, "You require two weapons to use this talent.") end return false end return true end,
 	action = function(self, t)
-		local dam, swap = doWardenWeaponSwap(self, t, t.getDamage(self, t))
+		local swap, dam = doWardenWeaponSwap(self, t, t.getDamage(self, t), "blade")
 
 		local tg = self:getTalentTarget(t)
 		local x, y, target = self:getTarget(tg)
@@ -193,39 +180,69 @@ newTalent{
 		local hitted = self:attackTarget(target, nil, dam, true)
 
 		if hitted then
-			-- Get available targets
-			local tgts = {}
-			local grids = core.fov.circle_grids(self.x, self.y, 10, true)
-			for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do
-				local target_type = Map.ACTOR
-				local a = game.level.map(x, y, Map.ACTOR)
-				if a and self:reactionToward(a) < 0 and self:hasLOS(a.x, a.y) then
-					tgts[#tgts+1] = a
-					print("Temporal Assault Target %s", a.name)
-				end
-			end end
-
-			-- Randomly take targets
+			bow_warden(self, target)
+			
 			local teleports = t.getTeleports(self, t)
 			local attempts = 10
-			while teleports > 0 and #tgts > 0 and attempts > 0 do
-				local a, id = rng.table(tgts)
-				-- since we're using a precise teleport we'll look for a free grid first
-				local tx2, ty2 = util.findFreeGrid(a.x, a.y, 5, true, {[Map.ACTOR]=true})
-				if tx2 and ty2 and not a.dead then
+			
+			-- Our teleport hit
+			local function teleport_hit(self, t, target, x, y)
+				local teleported = self:teleportRandom(x, y, 0)
+				if teleported then
 					game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
-					if not self:teleportRandom(tx2, ty2, 0) then
-						attempts = attempts - 1
+					if core.fov.distance(self.x, self.y, x, y) <= 1 then
+						self:attackTarget(target, nil, t.getDamage(self, t), true)
+					end
+				end
+				return teleported
+			end
+			
+			-- Check for Warden's focus
+			local wf = checkWardenFocus(self)
+			if wf and not wf.dead then
+				while teleports > 0 and attempts > 0 do
+					local tx, ty = util.findFreeGrid(wf.x, wf.y, 1, true, {[Map.ACTOR]=true})
+					if tx and ty and not wf.dead then
+						if teleport_hit(self, t, wf, tx, ty) then
+							teleports = teleports - 1
+						else
+							attempts = attempts - 1
+						end
 					else
-						game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
-						if core.fov.distance(self.x, self.y, a.x, a.y) <= 1 then
-							self:attackTarget(a, nil, dam, true)
+						break
+					end
+				end				
+			end
+			
+			-- Be sure we still have teleports left
+			if teleports > 0 and attempts > 0 then
+				-- Get available targets
+				local tgts = {}
+				local grids = core.fov.circle_grids(self.x, self.y, 10, true)
+				for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do
+					local target_type = Map.ACTOR
+					local a = game.level.map(x, y, Map.ACTOR)
+					if a and self:reactionToward(a) < 0 and self:hasLOS(a.x, a.y) then
+						tgts[#tgts+1] = a
+					end
+				end end
+
+				-- Randomly take targets
+				while teleports > 0 and #tgts > 0 and attempts > 0 do
+					local a, id = rng.table(tgts)
+					local tx2, ty2 = util.findFreeGrid(a.x, a.y, 1, true, {[Map.ACTOR]=true})
+					if tx2 and ty2 and not a.dead then
+						if teleport_hit(self, t, a, tx2, ty2) then
 							teleports = teleports - 1
+						else
+							attempts = attempts - 1
 						end
+					else
+						-- find a different target?
+						attempts = attempts - 1
 					end
-				else
-					attempts = attempts - 1
 				end
+			
 			end
 		end
 
@@ -236,8 +253,95 @@ newTalent{
 	info = function(self, t)
 		local damage = t.getDamage(self, t) * 100
 		local teleports = t.getTeleports(self, t)
-		return ([[Attack the target with your melee weapons for %d%% damage.  If the attack hits you'll teleport next to up to %d random enemies, attacking for %d%% damage.
-		Temporal Assault can hit the same target multiple times and at talent level five you get an additional teleport.]])
+		return ([[Attack with your melee weapons for %d%% damage.  If either weapon hits you'll teleport next to up to %d random enemies, attacking for %d%% damage.
+		Blink Blade can hit the same target multiple times and at talent level five you get an additional teleport.]])
 		:format(damage, teleports, damage)
 	end
 }
+
+newTalent{
+	name = "Blade Shear",
+	type = {"chronomancy/blade-threading", 4},
+	require = chrono_req4,
+	points = 5,
+	cooldown = 12,
+	paradox = function (self, t) return getParadoxCost(self, t, 18) end,
+	tactical = { ATTACK = {weapon = 2}, ATTACKAREA = { TEMPORAL = 2 }},
+	requires_target = true,
+	speed = "weapon",
+	range = 1,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 4.5, 6.5)) end,
+	is_melee = true,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	getShear = function(self, t) return self:combatTalentSpellDamage(t, 20, 200, getParadoxSpellpower(self, t)) end,
+	target = function(self, t)
+		return {type="cone", range=0, radius=self:getTalentRadius(t), talent=t, selffire=false }
+	end,
+	on_pre_use = function(self, t, silent) if not doWardenPreUse(self, "dual") then if not silent then game.logPlayer(self, "You require two weapons to use this talent.") end return false end return true end,
+	action = function(self, t)
+		local swap, dam = doWardenWeaponSwap(self, t, t.getDamage(self, t), "blade")
+		local tg = self:getTalentTarget(t)
+		local x, y = self:getTarget(tg)
+	
+		if not x or not y then
+			if swap then doWardenWeaponSwap(self, t, nil, "bow") end
+			return nil
+		end
+	
+		-- Change our radius for the melee attacks
+		local old_radius = tg.radius
+		tg.radius = 1
+		
+		-- Project our melee hits
+		local total_hits = 0
+		local bow_done = false
+		self:project(tg, x, y, function(px, py, tg, self)
+			local target = game.level.map(px, py, Map.ACTOR)
+			if target then
+				local hit = self:attackTarget(target, nil, t.getDamage(self, t), true)
+				if hit then
+					total_hits = total_hits + 1
+				end
+				if not bow_done then
+					bow_done = true
+					bow_warden(self, target)
+				end
+			end
+		end)
+
+		if total_hits > 0 then
+			-- Project our shear
+			local multi = (total_hits - 1)/2
+			local damage = self:spellCrit(t.getShear(self, t)) * (1 + multi)
+			tg.radius = self:getTalentRadius(t)
+		
+			self:project(tg, x, y, function(px, py, tg, self)
+				DamageType:get(DamageType.TEMPORAL).projector(self, px, py, DamageType.TEMPORAL, damage)
+				local target = game.level.map(px, py, Map.ACTOR)
+				-- Try to insta-kill
+				if target then
+					if target:checkHit(getParadoxSpellpower(self, t), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
+						-- KILL IT !
+						game.logSeen(target, "%s has been cut from the timeline!", target.name:capitalize())
+						target:die(self)
+					elseif target.life > 0 and target.life < target.max_life * 0.2 then
+						game.logSeen(target, "%s resists the temporal shear!", target.name:capitalize())
+					end
+				end
+			end)
+			game.level.map:particleEmitter(self.x, self.y, tg.radius, "temporal_breath", {radius=tg.radius, tx=x-self.x, ty=y-self.y})
+			game:playSoundNear(self, "talents/tidalwave")
+		end
+
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t) * 100
+		local shear = t.getShear(self, t)
+		local radius = self:getTalentRadius(t)
+		return ([[Attack up to three adjacent targets for %d%% weapon damage.  If any attack hits you'll create a temporal shear dealing %0.2f temporal damage in a radius %d cone.
+		Each target you hit with your weapons beyond the first increases the damage of the shear by 50%%.  Targets reduced below 20%% of maximum life by the shear may be instantly slain.
+		The cone damage improves with your Spellpower.]])
+		:format(damage, damDesc(self, DamageType.TEMPORAL, shear), radius)
+	end
+}
diff --git a/game/modules/tome/data/talents/chronomancy/bow-threading.lua b/game/modules/tome/data/talents/chronomancy/bow-threading.lua
index 8adea93b5b2090ee0a4323feb3d0c991e03698d5..5d541a46c209dc6c6cf1f899959a3e931e8eb7b7 100644
--- a/game/modules/tome/data/talents/chronomancy/bow-threading.lua
+++ b/game/modules/tome/data/talents/chronomancy/bow-threading.lua
@@ -19,61 +19,138 @@
 
 -- EDGE TODO: Particles, Timed Effect Particles
 
+local function blade_warden(self, target)
+	if self:knowTalent(self.T_WARDEN_S_CALL) then self:callTalent(self.T_WARDEN_S_CALL, "doBladeWarden", target) end
+end
+
 newTalent{
-	name = "Impact",
+	name = "Threaded Arrow",
 	type = {"chronomancy/bow-threading", 1},
-	mode = "sustained",
 	require = chrono_req1,
-	sustain_paradox = 12,
-	cooldown = 10,
-	tactical = { BUFF = 2 },
 	points = 5,
-	getDamage = function(self, t) return 7 + self:combatSpellpower(0.092) * self:combatTalentScale(t, 1, 7) end,
-	getApplyPower = function(self, t) return getParadoxSpellpower(self, t) end,
-	activate = function(self, t)
-		return {}
+	cooldown = 4,
+	tactical = { ATTACK = {weapon = 2} },
+	requires_target = true,
+	range = archery_range,
+	speed = 'archery',
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 2.2) end,
+	getParadoxReduction = function(self, t) return math.floor(self:combatTalentScale(t, 10, 20)) end,
+	on_pre_use = function(self, t, silent) if not doWardenPreUse(self, "bow") then if not silent then game.logPlayer(self, "You require a bow to use this talent.") end return false end return true end,
+	passives = function(self, t, p)
+		self:talentTemporaryValue(p,"archery_pass_friendly", 1)
 	end,
-	deactivate = function(self, t, p)
+	archery_onhit = function(self, t, target, x, y)
+		local dox = self:getParadox() - self.preferred_paradox
+		local fix = math.min( math.abs(dox), t.getParadoxReduction(self, t) )
+		if dox > 0 then
+			self:incParadox( -fix )
+		elseif dox < 0 then
+			self:incParadox( fix )
+		end
+		game:onTickEnd(function()blade_warden(self, target)end)
+	end,
+	action = function(self, t)
+		local swap, dam = doWardenWeaponSwap(self, t, t.getDamage(self, t), "bow")
+
+		local targets = self:archeryAcquireTargets({type="bolt"}, {one_shot=true, infinite=true, no_energy = true})
+		if not targets then if swap then doWardenWeaponSwap(self, t, nil, "blade") end return end
+		self:archeryShoot(targets, t, {type="bolt"}, {mult=dam, damtype=DamageType.TEMPORAL})
+
 		return true
 	end,
 	info = function(self, t)
-		local damage = t.getDamage(self, t)
-		return ([[Your weapons and ammo hit with greater force, dealing an additional %0.2f physical damage and having a %d%% chance to daze on hit.
-		The daze chance and damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.PHYSICAL, damage), math.min(25, damage/2))
-	end,
+		local damage = t.getDamage(self, t) * 100
+		local paradox = t.getParadoxReduction(self, t)
+		return ([[Fire an arrow for %d%% temporal weapon damage.  If the attack hits tune your Paradox up to %d towards your baseline.  This attack does not consume ammo.
+		You also learn how to phase your arrows through friendly targets without causing them harm.]])
+		:format(damage, paradox)
+	end
 }
 
 newTalent{
-	name = "Threaded Arrow",
+	name = "Arrow Stitching",
 	type = {"chronomancy/bow-threading", 2},
 	require = chrono_req2,
 	points = 5,
-	cooldown = 4,
-	tactical = { ATTACK = {weapon = 2} },
+	cooldown = 6,
+	paradox = function (self, t) return getParadoxCost(self, t, 12) end,
+	tactical = { ATTACK = {weapon = 4} },
 	requires_target = true,
 	range = archery_range,
 	speed = 'archery',
-	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 2.2) end,
-	getParadoxReduction = function(self, t) return math.floor(self:combatTalentScale(t, 10, 20)) end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	getClones = function(self, t) return self:getTalentLevel(t) >= 5 and 3 or self:getTalentLevel(t) >= 3 and 2 or 1 end,
+	target = function(self, t)
+		return {type="bolt", range=self:getTalentRange(t), talent=t, friendlyfire=false, friendlyblock=false}
+	end,
 	on_pre_use = function(self, t, silent) if not doWardenPreUse(self, "bow") then if not silent then game.logPlayer(self, "You require a bow to use this talent.") end return false end return true end,
 	archery_onhit = function(self, t, target, x, y)
-		self:incParadox(-t.getParadoxReduction(self, t))
+		game:onTickEnd(function()blade_warden(self, target)end)
 	end,
 	action = function(self, t)
-		local dam, swap = doWardenWeaponSwap(self, t, t.getDamage(self, t))
-
-		local targets = self:archeryAcquireTargets({type="bolt"}, {one_shot=true, infinite=true, no_energy = true})
-		if not targets then if swap then doWardenWeaponSwap(self, t, nil, "blade") end return end
-		self:archeryShoot(targets, t, {type="bolt"}, {mult=dam, damtype=DamageType.TEMPORAL})
+		local swap, dam = doWardenWeaponSwap(self, t, t.getDamage(self, t), "bow")
+		
+		-- Grab our target so we can spawn clones
+		local tg = self:getTalentTarget(t)
+		local x, y, target = self:getTarget(tg)
+		if not x or not y or not target then if swap == true then doWardenWeaponSwap(self, t, nil, "blade") end return nil end
+		local __, x, y = self:canProject(tg, x, y)
+		
+		-- Don't cheese arrow stitching through walls
+		if not self:hasLOS(x, y) then
+			game.logSeen(self, "You do not have line of sight.")
+			return nil
+		end
+				
+		local targets = self:archeryAcquireTargets(self:getTalentTarget(t), {one_shot=true, x=x, y=y, no_energy = true})
+		if not targets then return end
+		self:archeryShoot(targets, t, {type="bolt", friendlyfire=false, friendlyblock=false}, {mult=dam})
+		
+		-- Summon our clones
+		if not self.arrow_stitching_done then
+			for i = 1, t.getClones(self, t) do
+				local m = makeParadoxClone(self, self, 2)
+				local poss = {}
+				local range = self:getTalentRange(t)
+				for i = x - range, x + range do
+					for j = y - range, y + range do
+						if game.level.map:isBound(i, j) and
+							core.fov.distance(x, y, i, j) <= range and -- make sure they're within arrow range
+							core.fov.distance(i, j, self.x, self.y) <= range/2 and -- try to place them close to the caster so enemies dodge less
+							self:canMove(i, j) and target:hasLOS(i, j) then
+							poss[#poss+1] = {i,j}
+						end
+					end
+				end
+				if #poss == 0 then break  end
+				local pos = poss[rng.range(1, #poss)]
+				x, y = pos[1], pos[2]
+				game.zone:addEntity(game.level, m, "actor", x, y)
+				m.arrow_stitched_target = target
+				m.generic_damage_penalty = 50
+				m.energy.value = 1000
+				m:attr("archery_pass_friendly", 1)
+				m.on_act = function(self)
+					if not self.arrow_stitched_target.dead then
+						self.arrow_stitching_done = true
+						self:forceUseTalent(self.T_ARROW_STITCHING, {force_level=t.level, ignore_cd=true, ignore_energy=true, force_target=self.arrow_stitched_target, ignore_ressources=true, silent=true})
+						self:useEnergy()
+					end
+					game:onTickEnd(function()self:die()end)
+					game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
+				end
+			end
+		end
 
 		return true
 	end,
 	info = function(self, t)
-		local paradox = t.getParadoxReduction(self, t)
 		local damage = t.getDamage(self, t) * 100
-		return ([[Fire a shot doing %d%% temporal damage.  If the arrow hits you recover %d Paradox.
-		This attack does not consume ammo.]])
-		:format(damage, paradox)
+		local clones = t.getClones(self, t)
+		return ([[Fire an arrow for %d%% weapon damage and call up to %d wardens (depending on available space) that will each fire a single arrow before returning to their timelines.
+		The wardens are out of phase with normal reality and deal 50%% damage but shoot through friendly targets.
+		At talent level three and five you can summon an additional clone.]])
+		:format(damage, clones)
 	end
 }
 
@@ -83,7 +160,7 @@ newTalent{
 	require = chrono_req3,
 	points = 5,
 	cooldown = 10,
-	paradox = function (self, t) return getParadoxCost(self, t, 15) end,
+	paradox = function (self, t) return getParadoxCost(self, t, 18) end,
 	tactical = { ATTACKAREA = {PHYSICAL = 2}, DISABLE = 2 },
 	requires_target = true,
 	range = archery_range,
@@ -92,9 +169,12 @@ newTalent{
 	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
 	getDamageAoE = function(self, t) return self:combatTalentSpellDamage(t, 25, 290, getParadoxSpellpower(self, t)) end,
 	target = function(self, t)
-		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t}
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, friendlyfire=false, friendlyblock=false}
 	end,
 	on_pre_use = function(self, t, silent) if not doWardenPreUse(self, "bow") then if not silent then game.logPlayer(self, "You require a bow to use this talent.") end return false end return true end,
+	archery_onhit = function(self, t, target, x, y)
+		game:onTickEnd(function()blade_warden(self, target)end)
+	end,
 	archery_onreach = function(self, t, x, y)
 		game:onTickEnd(function() -- Let the arrow hit first
 			local tg = self:getTalentTarget(t)
@@ -146,7 +226,7 @@ newTalent{
 		end)
 	end,
 	action = function(self, t)
-		local dam, swap = doWardenWeaponSwap(self, t, t.getDamage(self, t))
+		local swap, dam = doWardenWeaponSwap(self, t, t.getDamage(self, t), "bow")
 		
 		-- Pull x, y from getTarget and pass it so we can show the player the area of effect
 		local tg = self:getTalentTarget(t)
@@ -165,7 +245,7 @@ newTalent{
 		local damage = t.getDamage(self, t) * 100
 		local radius = self:getTalentRadius(t)
 		local aoe = t.getDamageAoE(self, t)
-		return ([[Fire a shot doing %d%% damage.  When the arrow reaches its destination it will draw in creatures in a radius of %d and inflict %0.2f physical damage.
+		return ([[Fire an arrow for %d%% weapon damage.  When the arrow reaches its destination it will draw in enemies in a radius of %d and inflict %0.2f physical damage.
 		Each target moved beyond the first deals an additional %0.2f physical damage (up to %0.2f bonus damage).
 		Targets take reduced damage the further they are from the epicenter (20%% less per tile).
 		The additional damage scales with your Spellpower.]])
@@ -174,85 +254,66 @@ newTalent{
 }
 
 newTalent{
-	name = "Arrow Stitching",
+	name = "Arrow Echoes",
 	type = {"chronomancy/bow-threading", 4},
 	require = chrono_req4,
 	points = 5,
 	cooldown = 12,
-	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
+	paradox = function (self, t) return getParadoxCost(self, t, 24) end,
 	tactical = { ATTACK = {weapon = 4} },
 	requires_target = true,
 	range = archery_range,
-	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.3, 3.7)) end,
 	speed = 'archery',
-	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
-	getClones = function(self, t) return self:getTalentLevel(t) >= 5 and 3 or self:getTalentLevel(t) >= 3 and 2 or 1 end,
 	target = function(self, t)
 		return {type="bolt", range=self:getTalentRange(t), talent=t, friendlyfire=false, friendlyblock=false}
 	end,
-	on_pre_use = function(self, t, silent) if not doWardenPreUse(self, "bow") then if not silent then game.logPlayer(self, "You require a bow to use this talent.") end return false end return true end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 2, 4))) end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	archery_onhit = function(self, t, target, x, y)
+		game:onTickEnd(function() blade_warden(self, target) end)
+	end,
+	doEcho = function(self, t, eff)
+		game:onTickEnd(function()
+			local swap = doWardenWeaponSwap(self, t, nil, "bow", true)
+			local target = eff.target
+			local targets = self:archeryAcquireTargets({type="bolt"}, {one_shot=true, x=target.x, y=target.y, infinite=true, no_energy = true})
+			if not targets then
+			if swap == true then doWardenWeaponSwap(self, t, nil, "blade", true) end
+				return 
+			end
+			
+			self:archeryShoot(targets, t, {type="bolt", start_x=eff.x, start_y=eff.y}, {mult=t.getDamage(self, t)})
+			eff.shots = eff.shots - 1
+		end)
+	end,
 	action = function(self, t)
-		local dam, swap = doWardenWeaponSwap(self, t, t.getDamage(self, t))
+		local swap, dam = doWardenWeaponSwap(self, t, t.getDamage(self, t), "bow")
 		
-		-- Grab our target so we can spawn clones
+		-- Grab our target so we can set our echo
 		local tg = self:getTalentTarget(t)
 		local x, y, target = self:getTarget(tg)
 		if not x or not y or not target then if swap == true then doWardenWeaponSwap(self, t, nil, "blade") end return nil end
 		local __, x, y = self:canProject(tg, x, y)
 		
-		-- Don't cheese arrow stitching through walls
+		-- Sanity check
 		if not self:hasLOS(x, y) then
 			game.logSeen(self, "You do not have line of sight.")
 			return nil
 		end
-				
-		local targets = self:archeryAcquireTargets(self:getTalentTarget(t), {one_shot=true, x=x, y=y, no_energy = true})
+		
+		self:setEffect(self.EFF_ARROW_ECHOES, t.getDuration(self, t), {shots=t.getDuration(self, t), x=self.x, y=self.y, target=target})
+		
+		local targets = self:archeryAcquireTargets(self:getTalentTarget(t), {one_shot=true, x=x, y=y, no_energy=true})
 		if not targets then return end
-		self:archeryShoot(targets, t, {type="bolt", friendlyfire=false, friendlyblock=false}, {mult=dam})
+		self:archeryShoot(targets, t, {type="bolt"}, {mult=dam})
 		
-		-- Summon our clones
-		if not self.arrow_stitched_clone then
-			for i = 1, t.getClones(self, t) do
-				local m = makeParadoxClone(self, self, 2)
-				local poss = {}
-				local range = self:getTalentRange(t)
-				for i = x - range, x + range do
-					for j = y - range, y + range do
-						if game.level.map:isBound(i, j) and
-							core.fov.distance(x, y, i, j) <= range and -- make sure they're within arrow range
-							core.fov.distance(i, j, self.x, self.y) <= range/2 and -- try to place them close to the caster so enemies dodge less
-							self:canMove(i, j) and target:hasLOS(i, j) then
-							poss[#poss+1] = {i,j}
-						end
-					end
-				end
-				if #poss == 0 then break  end
-				local pos = poss[rng.range(1, #poss)]
-				x, y = pos[1], pos[2]
-				game.zone:addEntity(game.level, m, "actor", x, y)
-				m.shoot_target = target
-				m.arrow_stitched_clone = true
-				m.generic_damage_penalty = 50
-				m.energy.value = 1000
-				m:attr("archery_pass_friendly", 1)
-				m.on_act = function(self)
-					if not self.shoot_target.dead then
-						self:forceUseTalent(self.T_ARROW_STITCHING, {force_level=t.leve, ignore_cd=true, ignore_energy=true, force_target=self.shoot_target, ignore_ressources=true, silent=true})
-					end
-					self:die()
-					game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
-				end
-			end
-		end
-
 		return true
 	end,
 	info = function(self, t)
+		local duration = t.getDuration(self, t)
 		local damage = t.getDamage(self, t) * 100
-		local clones = t.getClones(self, t)
-		return ([[Fire upon the target for %d%% damage and summon up to %d temporal clones (depending on available space).
-		These clones are out of phase with normal reality and deal 50%% damage but shoot through friendly targets.
-		At talent level three and five you can summon an additional clone.]])
-		:format(damage, clones)
+		return ([[Fire an arrow for %d%% weapon damage at the target.  Over the next %d turns you'll fire up to %d additional arrows at this target from your original location.
+		These echoed shots do not consume ammo.]])
+		:format(damage, duration, duration)
 	end
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/chronomancy/chronomancer.lua b/game/modules/tome/data/talents/chronomancy/chronomancer.lua
index 6dbc99365366dcf36f16dd3636d9537cbe35788d..f737d25fdb2e9ed966704e351b8ce4e142e071f4 100644
--- a/game/modules/tome/data/talents/chronomancy/chronomancer.lua
+++ b/game/modules/tome/data/talents/chronomancy/chronomancer.lua
@@ -20,33 +20,34 @@
 -- Class Trees
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/blade-threading", name = "Blade Threading", description = "A blend of chronomancy and dual-weapon combat." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/bow-threading", name = "Bow Threading", description = "A blend of chronomancy and ranged combat." }
+newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/temporal-combat", name = "Temporal Combat", description = "A blend of chronomancy and physical combat." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/guardian", name = "Temporal Guardian", description = "Warden combat training and techniques." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/threaded-combat", name = "Threaded Combat", min_lev = 10, description = "A blend of ranged and dual-weapon combat." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/temporal-hounds", name = "Temporal Hounds", min_lev = 10, description = "Call temporal hounds to aid you in combat." }
 
-newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/fate-threading", name = "Fate Threading", description = "Manipulate the threads of fate." }
+newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/flux", name = "flux", description = "Fluctuate spacetime." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/gravity", name = "gravity", description = "Call upon the force of gravity to crush, push, and pull your foes." }
+newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/matter", name = "matter", description = "Change and shape matter itself." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/spacetime-folding", name = "Spacetime Folding", description = "Mastery of folding points in space." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/speed-control", name = "Speed Control", description = "Control how fast objects and creatures move through spacetime." }
-newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/timeline-threading", name = "Timeline Threading", description = "Examine and alter the timelines that make up the spacetime continuum." }
+newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/stasis", name = "stasis", description = "Stabilize spacetime." }
+newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/timeline-threading", name = "Timeline Threading", min_lev = 10, description = "Examine and alter the timelines that make up the spacetime continuum." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/timetravel", name = "timetravel", description = "Directly manipulate the flow of time" }
-newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/spatial-tears", name = "Spatial Tears", min_lev = 10, description = "Manipulate topological defects in the fabric of spacetime." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/spellbinding", name = "Spellbinding", min_lev = 10, description = "Manipulate chronomantic spells." }
 
 -- Generic Chronomancy
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/chronomancy", name = "Chronomancy", generic = true, description = "Allows you to glimpse the future, or become more aware of the present." }
-newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/energy", name = "energy", generic = true, min_lev = 10, description = "Manipulate raw energy by addition or subtraction." }
+newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/energy", name = "energy", generic = true, description = "Manipulate raw energy by addition or subtraction." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/fate-weaving", name = "Fate Weaving", generic = true, description = "Weave the threads of fate." }
 newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/spacetime-weaving", name = "Spacetime Weaving", generic = true, description = "Weave the threads of spacetime." }
 
 -- Misc and Outdated Trees
+newTalentType{ no_silence=true, is_spell=true, type="chronomancy/manifold", name = "Manifold", generic = true, description = "Passive effects that Weapon Folding can trigger." }
 newTalentType{ no_silence=true, is_spell=true, type="chronomancy/other", name = "Other", generic = true, description = "Miscellaneous Chronomancy effects." }
 
 newTalentType{ no_silence=true, is_spell=true, type="chronomancy/age-manipulation", name = "Age Manipulation", description = "Manipulate the age of creatures you encounter." }
-newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/matter", name = "matter", description = "Change and shape matter itself." }
-newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/paradox", name = "paradox", description = "Break the laws of spacetime." }
 newTalentType{ no_silence=true, is_spell=true, type="chronomancy/temporal-archery", name = "Temporal Archery", description = "A blend of chronomancy and ranged combat." }
-newTalentType{ no_silence=true, is_spell=true, type="chronomancy/temporal-combat", name = "Temporal Combat", description = "A blend of chronomancy and physical combat." }
+newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="chronomancy/paradox", name = "paradox", description = "Break the laws of spacetime." }
 
 -- Anomalies are not learnable but can occur instead of an intended spell when paradox gets to high.
 newTalentType{ no_silence=true, is_spell=true, type="chronomancy/anomalies", name = "anomalies", description = "Spacetime anomalies that can randomly occur when paradox is to high." }
@@ -121,23 +122,23 @@ load("/data/talents/chronomancy/blade-threading.lua")
 load("/data/talents/chronomancy/bow-threading.lua")
 load("/data/talents/chronomancy/chronomancy.lua")
 load("/data/talents/chronomancy/energy.lua")
-load("/data/talents/chronomancy/fate-threading.lua")
 load("/data/talents/chronomancy/fate-weaving.lua")
+load("/data/talents/chronomancy/flux.lua")
 load("/data/talents/chronomancy/gravity.lua")
+load("/data/talents/chronomancy/guardian.lua")
 load("/data/talents/chronomancy/matter.lua")
 load("/data/talents/chronomancy/paradox.lua")
+load("/data/talents/chronomancy/spacetime-folding.lua")
+load("/data/talents/chronomancy/spacetime-weaving.lua")
 load("/data/talents/chronomancy/speed-control.lua")
 load("/data/talents/chronomancy/spellbinding.lua")
+load("/data/talents/chronomancy/stasis.lua")
 load("/data/talents/chronomancy/temporal-archery.lua")
 load("/data/talents/chronomancy/temporal-combat.lua")
-load("/data/talents/chronomancy/guardian.lua")
 load("/data/talents/chronomancy/temporal-hounds.lua")
 load("/data/talents/chronomancy/threaded-combat.lua")
 load("/data/talents/chronomancy/timeline-threading.lua")
 load("/data/talents/chronomancy/timetravel.lua")
-load("/data/talents/chronomancy/spacetime-folding.lua")
-load("/data/talents/chronomancy/spacetime-weaving.lua")
-load("/data/talents/chronomancy/spatial-tears.lua")
 
 -- Loads many functions and misc. talents
 load("/data/talents/chronomancy/other.lua")
diff --git a/game/modules/tome/data/talents/chronomancy/chronomancy.lua b/game/modules/tome/data/talents/chronomancy/chronomancy.lua
index 0cda0c85f9b603fd778df0448943122c1ab726d5..1e10bb219bbe740b58268025a427e0e1af642fd3 100644
--- a/game/modules/tome/data/talents/chronomancy/chronomancy.lua
+++ b/game/modules/tome/data/talents/chronomancy/chronomancy.lua
@@ -111,7 +111,7 @@ newTalent{
 				p.rest_count = self:getTalentCooldown(t)
 				game:onTickEnd(function()
 					if not self.dead then
-						self:forceUseTalent(cont_t, {ignore_ressources=true, ignore_cd=true, ignore_energy=true, force_level=t_level})
+						self:forceUseTalent(cont_t, {ignore_ressources=true, ignore_cd=true, ignore_energy=true, force_target=self, force_level=t_level})
 					end
 				end)
 			end
@@ -151,10 +151,10 @@ newTalent{
 		local trigger = t.getTrigger(self, t) * 100
 		local cooldown = self:getTalentCooldown(t)
 		local talent = self:isTalentActive(t.id) and self:getTalentFromId(self:isTalentActive(t.id).talent).name or "None"
-		return ([[Choose an activatable spell that's not targeted.  When you take damage that reduces your life below %d%% the spell will automatically cast.
+		return ([[Choose an activatable spell that's not targeted and does not have a fixed cooldown.  When you take damage that reduces your life below %d%% the spell will automatically cast.
 		This spell will cast even if it is currently on cooldown, will not consume a turn or resources, and uses the talent level of Contingency or its own, whichever is lower.
 		This effect can only occur once every %d turns and takes place after the damage is resolved.
-		
+
 		Current Contingency Spell: %s]]):
 		format(trigger, cooldown, talent)
 	end,
@@ -168,9 +168,7 @@ newTalent{
 	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
 	cooldown = 50,
 	no_npc_use = true,  -- so rares don't learn useless talents
-	allow_temporal_clones = true,  -- let clones copy it anyway so they can benefit from the effects
-	on_pre_use = function(self, t, silent) if self ~= game.player then return false end return true end,  -- but don't let them cast it
-	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(self:getTalentLevel(t), 10, 25))) end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 10, 25))) end,
 	on_pre_use = function(self, t, silent)
 		if checkTimeline(self) then
 			if not silent then
diff --git a/game/modules/tome/data/talents/chronomancy/energy.lua b/game/modules/tome/data/talents/chronomancy/energy.lua
index 6b6c8117b7c385962f7004f0f42035d5886b8817..bbe45cc397037259f8351c7556e4390ed7d56952 100644
--- a/game/modules/tome/data/talents/chronomancy/energy.lua
+++ b/game/modules/tome/data/talents/chronomancy/energy.lua
@@ -23,7 +23,7 @@ newTalent{
 	name = "Energy Decomposition",
 	type = {"chronomancy/energy",1},
 	mode = "sustained",
-	require = chrono_req_high1,
+	require = chrono_req1,
 	points = 5,
 	sustain_paradox = 24,
 	cooldown = 10,
@@ -59,7 +59,7 @@ newTalent{
 newTalent{
 	name = "Energy Absorption",
 	type = {"chronomancy/energy", 2},
-	require = chrono_req_high2,
+	require = chrono_req2,
 	points = 5,
 	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
 	cooldown = 6,
@@ -71,7 +71,6 @@ newTalent{
 	getTalentCount = function(self, t)
 		return 1 + math.floor(self:combatTalentLimit(t, 3, 0, 2))
 	end,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 80, getParadoxSpellpower(self, t)) end,
 	getCooldown = function(self, t) return math.ceil(self:combatTalentScale(t, 1, 2.6)) end,
 	target = function (self, t)
 		return {type="hit", range=self:getTalentRange(t), talent=t}
@@ -120,9 +119,6 @@ newTalent{
 				local tid = rng.tableRemove(tids)
 				self:alterTalentCoolingdown(tid, - cdr)
 			end
-
-			-- Deal our damage in one lump sum
-			self:project(tg, target.x, target.y, DamageType.TEMPORAL, self:spellCrit(count * t.getDamage(self, t)))
 		end
 
 		target:crossTierEffect(target.EFF_SPELLSHOCKED, getParadoxSpellpower(self, t))
@@ -134,25 +130,23 @@ newTalent{
 	info = function(self, t)
 		local talentcount = t.getTalentCount(self, t)
 		local cooldown = t.getCooldown(self, t)
-		local damage = t.getDamage(self, t)
 		return ([[You sap the target's energy and add it to your own, placing up to %d random talents on cooldown for %d turns.
-		For each talent put on cooldown, you reduce the cooldown of one of your chronomancy talents currently on cooldown by %d turns and deal %0.2f temporal damage to the target.
-		The damage done will scale with your Spellpower.]]):
-		format(talentcount, cooldown, cooldown, damDesc(self, DamageType.TEMPORAL, damage))
+		For each talent put on cooldown, you reduce the cooldown of one of your chronomancy talents currently on cooldown by %d turns.]]):
+		format(talentcount, cooldown, cooldown)
 	end,
 }
 
 newTalent{
 	name = "Redux",
 	type = {"chronomancy/energy",3},
-	require = chrono_req_high3,
+	require = chrono_req3,
 	points = 5,
 	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
 	cooldown = 24,
 	tactical = { BUFF = 2 },
 	fixed_cooldown = true,
 	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 2, 4))) end,
-	getMaxCooldown = function(self, t) return math.floor(self:combatTalentScale(t, 3, 8)) end,
+	getMaxCooldown = function(self, t) return 1 + math.floor(self:combatTalentScale(t, 3, 8)) end,
 	action = function(self, t)
 		-- effect is handled in actor postUse
 		self:setEffect(self.EFF_REDUX, t.getDuration(self, t), {max_cd=t.getMaxCooldown(self, t)})
@@ -170,7 +164,7 @@ newTalent{
 newTalent{
 	name = "Entropy",
 	type = {"chronomancy/energy",4},
-	require = chrono_req_high4,
+	require = chrono_req4,
 	points = 5,
 	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
 	cooldown = 12,
diff --git a/game/modules/tome/data/talents/chronomancy/fate-weaving.lua b/game/modules/tome/data/talents/chronomancy/fate-weaving.lua
index 8aef9eb31cbc52e78f5cc64b0a2213732c8ac764..b7d2e7bb44e65918937a8d60d5d20472eaaf0205 100644
--- a/game/modules/tome/data/talents/chronomancy/fate-weaving.lua
+++ b/game/modules/tome/data/talents/chronomancy/fate-weaving.lua
@@ -26,27 +26,20 @@ newTalent{
 	mode = "passive",
 	points = 5,
 	getSaveBonus = function(self, t) return math.ceil(self:combatTalentScale(t, 2, 8, 0.75)) end,
+	getMaxSpin = function(self, t) return self:hasEffect(self.EFF_WEBS_OF_FATE) and 6 or 3 end,
+	doSpin = function(self, t)
+		self:setEffect(self.EFF_SPIN_FATE, 3, {save_bonus=t.getSaveBonus(self, t), spin=1, max_spin=t.getMaxSpin(self, t)})
+		
+		-- Fateweaver
+		if self:knowTalent(self.T_FATEWEAVER) then
+			self:callTalent(self.T_FATEWEAVER, "doFateweaver")
+		end
+	end,
 	callbackOnTakeDamage = function(self, t, src, x, y, type, dam, tmp)
 		if dam > 0 and src ~= self then
 			if self.turn_procs and not self.turn_procs.spin_fate then
-
-				self:setEffect(self.EFF_SPIN_FATE, 3, {save_bonus=t.getSaveBonus(self, t), spin=1, max_spin=3})
-
-				-- Set our turn procs, we do spin_fate last since it's the only one checked above
-				if self.hasEffect and self:hasEffect(self.EFF_WEBS_OF_FATE) and not self.turn_procs.spin_webs then
-					self.turn_procs.spin_webs = true
-				elseif self.hasEffect and self:hasEffect(self.EFF_SEAL_FATE) and not self.turn_procs.spin_seal then
-					self.turn_procs.spin_seal = true
-				else
-					self.turn_procs.spin_fate = true
-				end
-
-				-- Reduce damage if we know Fateweaver
-				if self:knowTalent(self.T_FATEWEAVER) then
-					local reduction = dam * self:callTalent(self.T_FATEWEAVER, "getReduction")
-					dam = dam - reduction
-					game:delayedLogDamage(src, self, 0, ("%s(%d fatewever)#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", reduction), false)
-				end
+				t.doSpin(self, t)
+				self.turn_procs.spin_fate = true
 			end
 		end
 
@@ -54,60 +47,33 @@ newTalent{
 	end,
 	info = function(self, t)
 		local save = t.getSaveBonus(self, t)
-		return ([[Each time you take damage from someone else you gain one spin, increasing your defense and saves by %d for three turns.
-		This effect may occur once per turn and stacks up to three spin (for a maximum bonus of %d).]]):
+		return ([[Each time you take damage from someone else you gain one Spin, increasing your defense and saves by %d for three turns.
+		This effect may occur once per turn and stacks up to three Spin (for a maximum bonus of %d).]]):
 		format(save, save * 3)
 	end,
 }
+
 newTalent{
-	name = "Webs of Fate",
+	name = "Seal Fate",
 	type = {"chronomancy/fate-weaving", 2},
 	require = chrono_req2,
 	points = 5,
 	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
 	cooldown = 12,
-	tactical = { BUFF = 2, CLOSEIN = 2, ESCAPE = 2 },
-	getPower = function(self, t) return paradoxTalentScale(self, t, 15, 30, 50)/100 end,
+	tactical = { BUFF = 2 },
 	getDuration = function(self, t) return getExtensionModifier(self, t, 5) end,
+	getProcs = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5)) end,
 	no_energy = true,
 	action = function(self, t)
-		local effs = {}
-
-		-- Find all pins
-		for eff_id, p in pairs(self.tmp) do
-			local e = self.tempeffect_def[eff_id]
-			if e.subtype.pin or e.subtype.stun then
-				effs[#effs+1] = {"effect", eff_id}
-			end
-		end
-
-		-- And remove them
-		while #effs > 0 do
-			local eff = rng.tableRemove(effs)
-
-			if eff[1] == "effect" then
-				self:removeEffect(eff[2])
-			end
-		end
-
-		-- Set our power based on current spin
-		local imm = t.getPower(self, t)
-		local eff = self:hasEffect(self.EFF_SPIN_FATE)
-		if eff then
-			imm = imm * (1 + eff.spin/3)
-		end
-
-		self:setEffect(self.EFF_WEBS_OF_FATE, t.getDuration(self, t), {imm=imm})
-
+		self:setEffect(self.EFF_SEAL_FATE, t.getDuration(self, t), {procs=t.getProcs(self, t)})
 		return true
 	end,
 	info = function(self, t)
-		local power = t.getPower(self, t) * 100
+		local procs = t.getProcs(self, t)
 		local duration = t.getDuration(self, t)
-		return ([[Activate to remove pins and stuns.  You also gain %d%% pin and stun immunity for %d turns.
-		If you have Spin Fate active these bonuses will be increased by 33%% per spin (up to a maximum of %d%%).
-		While Webs of Fate is active you may gain one additional spin per turn.  These bonuses will scale with your Spellpower.]])
-		:format(power, duration, power * 2)
+		return ([[Activate to Seal Fate for %d turns.  When you damage a target while Seal Fate is active you gain Spin and have a 50%% chance to increase the duration of one detrimental status effect on it by one turn.
+		If you have Spin Fate active the chance will be increased by 33%% per Spin (to a maximum of 100%% at three Spin.)
+		The duration increase can occur up to %d times per turn and the bonus Spin once per turn.]]):format(duration, procs)
 	end,
 }
 
@@ -117,35 +83,43 @@ newTalent{
 	require = chrono_req3,
 	mode = "passive",
 	points = 5,
-	getReduction = function(self, t) return paradoxTalentScale(self, t, 10, 30, 40)/100 end,
+	getPowerBonus = function(self, t) return math.ceil(self:combatTalentScale(t, 2, 8, 0.75)) end,
+	getMaxSpin = function(self, t) return self:hasEffect(self.EFF_WEBS_OF_FATE) and 6 or 3 end,
+	doFateweaver = function(self, t)
+		local eff = self:hasEffect(self.EFF_SPIN_FATE)
+		if not eff then return end
+		self:setEffect(self.EFF_FATEWEAVER, 3, {power_bonus=t.getPowerBonus(self, t), spin=1, max_spin=t.getMaxSpin(self, t)})
+	end,
 	info = function(self, t)
-		local reduction = t.getReduction(self, t)*100
-		return ([[When Spin Fate is triggered you reduce the triggering damage by %d%%.
-		This effect scales with your Spellpower.]]):
-		format(reduction)
+		local power = t.getPowerBonus(self, t)
+		return ([[You now gain %d combat accuracy, physical power, spellpower, and mindpower per Spin.]]):
+		format(power)
 	end,
 }
 
 newTalent{
-	name = "Seal Fate",
+	name = "Webs of Fate",
 	type = {"chronomancy/fate-weaving", 4},
 	require = chrono_req4,
 	points = 5,
 	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
-	cooldown = 24,
-	tactical = { BUFF = 2 },
+	cooldown = 12,
+	tactical = { BUFF = 2, DEFEND = 2 },
+	range = 10,
+	getPower = function(self, t) return self:combatTalentLimit(t, 50, 10, 30)/100 end, -- Limit < 50%
 	getDuration = function(self, t) return getExtensionModifier(self, t, 5) end,
-	getProcs = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5)) end,
 	no_energy = true,
 	action = function(self, t)
-		self:setEffect(self.EFF_SEAL_FATE, t.getDuration(self, t), {procs=t.getProcs(self, t)})
+	
+		self:setEffect(self.EFF_WEBS_OF_FATE, t.getDuration(self, t), {power=t.getPower(self, t), talent=t})
+		
 		return true
 	end,
 	info = function(self, t)
-		local procs = t.getProcs(self, t)
+		local power = t.getPower(self, t) * 100
 		local duration = t.getDuration(self, t)
-		return ([[Activate to Seal Fate for %d turns.  When you damage a target while Seal Fate is active you have a 50%% chance to increase the duration of one detrimental status effect on it by one turn.
-		If you have Spin Fate active the chance will be increased by 33%% per Spin (to a maximum of 100%% at three Spin.)
-		This can occur at most %d times per turn.  While Seal Fate is active you may gain one additional spin per turn.]]):format(duration, procs)
+		return ([[For the next %d turns you displace %d%% of any damage you receive onto a random enemy within range.
+		While Webs of Fate is active you may gain one additional Spin per turn and your maximum Spin is doubled.]])
+		:format(duration, power)
 	end,
 }
diff --git a/game/modules/tome/data/talents/chronomancy/fate-threading.lua b/game/modules/tome/data/talents/chronomancy/flux.lua
similarity index 66%
rename from game/modules/tome/data/talents/chronomancy/fate-threading.lua
rename to game/modules/tome/data/talents/chronomancy/flux.lua
index 3b59c41264415dc1499ab0aaef43794b19b57544..557fa7c49ea421a663dc38c0e193dc55eaf38d79 100644
--- a/game/modules/tome/data/talents/chronomancy/fate-threading.lua
+++ b/game/modules/tome/data/talents/chronomancy/flux.lua
@@ -20,8 +20,8 @@
 -- EDGE TODO: Particles, Timed Effect Particles
 
 newTalent{
-	name = "Disentangle",
-	type = {"chronomancy/fate-threading", 1},
+	name = "Induce Anomaly",
+	type = {"chronomancy/flux", 1},
 	require = chrono_req1,
 	points = 5,
 	cooldown = 12,
@@ -36,20 +36,21 @@ newTalent{
 	action = function(self, t)
 		local reduction = self:spellCrit(t.getReduction(self, t))
 		self:paradoxDoAnomaly(reduction, t.anomaly_type, "forced")
+		game:playSoundNear(self, "talents/echo")
 		return true
 	end,
 	info = function(self, t)
 		local reduction = t.getReduction(self, t)
 		local paradox = 100 * t.getParadoxMulti(self, t)
-		return ([[Disentangle the timeline, reducing your Paradox by %d and creating an anomaly.  This spell will never produce a major anomaly.
-		Additionally you recover %d%% more Paradox from random anomalies (%d%% total).
+		return ([[Create an anomaly, reducing your Paradox by %d.  This spell will never produce a major anomaly.
+		Additionally you recover %d%% more Paradox from random anomalies when they occur (%d%% total).
 		The Paradox reduction will increase with your Spellpower.]]):format(reduction, paradox, paradox + 200)
 	end,
 }
 
 newTalent{
-	name = "Preserve Pattern",
-	type = {"chronomancy/fate-threading", 2},
+	name = "Reality Smearing",
+	type = {"chronomancy/flux", 2},
 	require = chrono_req2,
 	mode = "sustained", 
 	sustain_paradox = 0,
@@ -73,15 +74,16 @@ newTalent{
 		local fnt = "buff_font"
 		return tostring(math.ceil(val)), fnt
 	end,
-	doPerservePattern = function(self, t, src, dam)
-		local absorb = dam * t.getPercent(self, t)
+	callbackOnHit = function(self, t, cb, src)
+		local absorb = cb.value * t.getPercent(self, t)
 		local paradox = absorb*t.getConversionRatio(self, t)
-		self:setEffect(self.EFF_PRESERVE_PATTERN, t.getDuration(self, t), {paradox=paradox/t.getDuration(self, t), no_ct_effect=true})
-		game:delayedLogMessage(self, nil,  "preserve pattern", "#LIGHT_BLUE##Source# converts damage to paradox!")
+		
+		self:setEffect(self.EFF_REALITY_SMEARING, t.getDuration(self, t), {paradox=paradox/t.getDuration(self, t), no_ct_effect=true})
+		game:delayedLogMessage(self, nil,  "reality smearing", "#LIGHT_BLUE##Source# converts damage to paradox!")
 		game:delayedLogDamage(src, self, 0, ("#LIGHT_BLUE#(%d converted)#LAST#"):format(absorb), false)
-		dam = dam - absorb
+		cb.value = cb.value - absorb
 		
-		return dam
+		return cb.value
 	end,
 	activate = function(self, t)
 		game:playSoundNear(self, "talents/arcane")
@@ -110,8 +112,8 @@ newTalent{
 }
 
 newTalent{
-	name = "Trim Threads",
-	type = {"chronomancy/fate-threading", 3},
+	name = "Attenuate",
+	type = {"chronomancy/flux", 3},
 	require = chrono_req3,
 	points = 5,
 	cooldown = 4,
@@ -128,7 +130,7 @@ newTalent{
 	direct_hit = true,
 	doAnomaly = function(self, t, target, eff)
 		self:project({type=hit}, target.x, target.y, DamageType.TEMPORAL, eff.power * eff.dur)
-		target:removeEffect(target.EFF_TRIM_THREADS)
+		target:removeEffect(target.EFF_ATTENUATE)
 	end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
@@ -140,11 +142,10 @@ newTalent{
 		self:project(tg, x, y, function(px, py)
 			local target = game.level.map(px, py, Map.ACTOR)
 			if not target then return end
-			target:setEffect(target.EFF_TRIM_THREADS, t.getDuration(self, t), {power=damage/4, src=self, reduction=t.getReduction(self, t), apply_power=getParadoxSpellpower(self, t)})
+			target:setEffect(target.EFF_ATTENUATE, t.getDuration(self, t), {power=damage/4, src=self, reduction=t.getReduction(self, t), apply_power=getParadoxSpellpower(self, t)})
 		end)
 
 		game.level.map:particleEmitter(x, y, tg.radius, "temporal_flash", {radius=tg.radius})
-
 		game:playSoundNear(self, "talents/tidalwave")
 
 		return true
@@ -161,51 +162,46 @@ newTalent{
 }
 
 newTalent{
-	name = "Bias Weave",
-	type = {"chronomancy/fate-threading", 4},
+	name = "Twist Fate",
+	type = {"chronomancy/flux", 4},
 	require = chrono_req4,
 	points = 5,
-	cooldown = 10,
-	-- Anomaly biases can be set manually for monsters
-	-- Use the following format anomaly_bias = { type = "teleport", chance=50}
-	no_npc_use = true,  -- so rares don't learn useless talents
-	allow_temporal_clones = true,  -- let clones copy it anyway so they can benefit from the effects
-	on_pre_use = function(self, t, silent) if self ~= game.player then return false end return true end,  -- but don't let them cast it
-	getBiasChance = function(self, t) return self:combatTalentLimit(t, 100, 10, 75) end,
-	getTargetChance = function(self, t) return self:combatTalentLimit(t, 100, 10, 75) end,
-	getAnomalySpeed = function(self, t) return self:combatTalentLimit(t, 1, 0.10, .75) end,
-	passives = function(self, t, p)
-		self:talentTemporaryValue(p, "anomaly_recovery_speed", t.getAnomalySpeed(self, t))
+	cooldown = 6,
+	tactical = { ATTACKAREA = 2 },
+	on_pre_use = function(self, t, silent) if not self:hasEffect(self.EFF_TWIST_FATE) then if not silent then game.logPlayer(self, "You must have a twisted anomaly to cast this spell.") end return false end return true end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 1, 5))) end,
+	doTwistFate = function(self, t, twist)
+		local eff = self:hasEffect(self.EFF_TWIST_FATE)
+		eff.twisted = twist or false
+		
+		-- Call the anomoly action function directly
+		local anom = self:getTalentFromId(eff.talent)
+		anom.action(self, anom)
+
+		self:incParadox(-eff.paradox)
+		self:removeEffect(self.EFF_TWIST_FATE)
 	end,
-	on_learn = function(self, t)
-		if self.anomaly_bias and self.anomaly_bias.chance then
-			self.anomaly_bias.chance = t.getBiasChance(self, t)
-		end
+	setEffect = function(self, t, talent, paradox)
+		game.logPlayer(self, "#STEEL_BLUE#You take control of %s.", self:getTalentFromId(talent).name or nil)
+		self:setEffect(self.EFF_TWIST_FATE, t.getDuration(self, t), {talent=talent, paradox=paradox})
+		
+		game.level.map:particleEmitter(self.x, self.y, 1, "generic_charge", {rm=70, rM=176, gm=130, gM=196, bm=180, bM=222, am=125, aM=125})
 	end,
- 	on_unlearn = function(self, t)
-		if self:getTalentLevel(t) == 0 then
-			self.anomaly_bias = nil
-		elseif self.anomaly_bias and self.anomaly_bias.chance then
-			self.anomaly_bias.chance = t.getBiasChance(self, t)
-		end
- 	end,
 	action = function(self, t)
-		local state = {}
-		local Chat = require("engine.Chat")
-		local chat = Chat.new("chronomancy-bias-weave", {name="Bias Weave"}, self, {version=self, state=state})
-		local d = chat:invoke()
-		local co = coroutine.running()
-		d.unload = function() coroutine.resume(co, state.set_bias) end
-		if not coroutine.yield() then return nil end
+		t.doTwistFate(self, t, true)
+		game:playSoundNear(self, "talents/echo")
 		return true
 	end,
 	info = function(self, t)
-		local target_chance = t.getTargetChance(self, t)
-		local bias_chance = t.getBiasChance(self, t)
-		local anomaly_recovery = (1 - t.getAnomalySpeed(self, t)) * 100
-		return ([[You've learned to focus most anomalies when they occur and may choose the target area with %d%% probability.
-		You also may bias the type of anomaly effects you produce with %d%% probability.
-		Additionally random anomalies only cost you %d%% of a turn rather than a full turn when they occur.
-		Major anomalies, those occuring when your modified Paradox is over 600, are not affected by this talent.]]):format(target_chance, bias_chance, anomaly_recovery)
+		local eff = self:hasEffect(self.EFF_TWIST_FATE)
+		local talent = "None"
+		if eff then talent = self:getTalentFromId(eff.talent).name end
+		local duration = t.getDuration(self, t)
+		return ([[If Twist Fate is not on cooldown minor anomalies will be held for %d turns, allowing your spell to cast as normal.  While held you may cast Twist Fate in order to trigger the anomaly and may choose the target area.
+		If a second anomaly occurs while a prior one is held or the timed effect expires the first anomaly will trigger immediately, interrupting your current turn or action.
+		Paradox reductions from held anomalies occur when triggered.
+				
+		Current Twisted Anomaly: %s]]):
+		format(duration, talent)
 	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/chronomancy/gravity.lua b/game/modules/tome/data/talents/chronomancy/gravity.lua
index 65aa4f69f75925d3b9df843756b98c2672a14145..bc7019d39036d41708dc7f7f239be785f6dfa3e8 100644
--- a/game/modules/tome/data/talents/chronomancy/gravity.lua
+++ b/game/modules/tome/data/talents/chronomancy/gravity.lua
@@ -25,7 +25,7 @@ newTalent{
 	require = chrono_req1,
 	points = 5,
 	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
-	cooldown = 3,
+	cooldown = 4,
 	tactical = { ATTACKAREA = {PHYSICAL = 2}, ESCAPE = 2 },
 	range = 0,
 	radius = function(self, t) return math.floor(self:combatTalentScale(t, 4.5, 6.5)) end,
@@ -57,6 +57,14 @@ newTalent{
 					end
 				end
 				
+				-- Apply anti-gravity?
+				if self:isTalentActive(self.T_GRAVITY_LOCUS) then
+					local chance = self:callTalent(self.T_GRAVITY_LOCUS, "getAnti")
+					if rng.percent(chance) then
+						target:setEffect(target.EFF_ANTI_GRAVITY, 2, {})
+					end
+				end
+				
 				local hit = target:checkHit(getParadoxSpellpower(self, t), target:combatPhysicalResist(), 0, 95) and target:canBe("knockback")
 					
 				if hit then
@@ -89,7 +97,7 @@ newTalent{
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		local radius = self:getTalentRadius(t)
-		return ([[Sends out a blast wave of gravity in a radius %d cone, dealing %0.2f base physical damage and knocking back targets caught in the area.
+		return ([[Sends out a blast wave of gravity in a radius %d cone, dealing %0.2f base physical (gravity) damage and knocking back targets caught in the area.
 		Targets knocked into walls or other targets take 50%% additional damage and deal 50%% damage to targets they're knocked into.
 		Closer targets will be knocked back further and the damage will scale with your Spellpower.]]):
 		format(radius, damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)))
@@ -102,7 +110,7 @@ newTalent{
 	require = chrono_req2,
 	points = 5,
 	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
-	cooldown = 4,
+	cooldown = 6,
 	tactical = { ATTACKAREA = {PHYSICAL = 2}, DISABLE = 2 },
 	range = 10,
 	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.3, 3.7)) end,
@@ -111,7 +119,7 @@ newTalent{
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t}
 	end,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 25, 290, getParadoxSpellpower(self, t)) end,
+	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 25, 230, getParadoxSpellpower(self, t)) end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
@@ -165,8 +173,8 @@ newTalent{
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		local radius = self:getTalentRadius(t)
-		return ([[Creates a gravity spike in a radius of %d that moves all targets towards the spell's center and inflicts %0.2f physical damage.
-		Each target moved beyond the first deals an additional %0.2f physical damage (up to %0.2f bonus damage).
+		return ([[Creates a gravity spike in a radius of %d that moves all targets towards the spell's center and inflicts %0.2f physical (gravity) damage.
+		Each target moved beyond the first deals an additional %0.2f physical (gravity) damage (up to %0.2f bonus damage).
 		Targets take reduced damage the further they are from the epicenter (20%% less per tile).
 		The damage dealt will scale with your Spellpower.]])
 		:format(radius, damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.PHYSICAL, damage/4), damDesc(self, DamageType.PHYSICAL, damage))
@@ -182,32 +190,32 @@ newTalent{
 	cooldown = 10,
 	tactical = { BUFF = 2 },
 	points = 5,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 50, getParadoxSpellpower(self, t)) end,
-	getSlow = function(self, t) return paradoxTalentScale(self, t, 20, 50, 80) end,
-	callbackOnMeleeHit = function(self, t, target)
-		if not self.dead and self:isTalentActive(self.T_GRAVITY_LOCUS) then
-			self:project({type="hit", talent=t}, target.x, target.y, DamageType.GRAVITY, {dam=t.getDamage(self, t), anti=true, dur=2, apply=getParadoxSpellpower(self, t)})
-		end
-	end,
+	getSlow = function(self, t) return self:combatTalentLimit(t, 80, 10, 50) end,
+	getAnti = function(self, t) return self:combatTalentLimit(t, 100, 10, 75) end,
+	getConversion= function(self, t) return self:combatTalentLimit(t, 100, 10, 75) end,
 	activate = function(self, t)
 		game:playSoundNear(self, "talents/heal")
 		local particle = Particles.new("ultrashield", 1, {rm=204, rM=220, gm=102, gM=120, bm=0, bM=0, am=35, aM=90, radius=0.5, density=10, life=28, instop=100})
 		return {
+			converttype = self:addTemporaryValue("all_damage_convert", DamageType.PHYSICAL),
+			convertamount = self:addTemporaryValue("all_damage_convert_percent", t.getConversion(self, t)),
 			proj = self:addTemporaryValue("slow_projectiles", t.getSlow(self, t)),
 			particle = self:addParticles(particle)
 		}
 	end,
 	deactivate = function(self, t, p)
+		self:removeTemporaryValue("all_damage_convert", p.converttype)
+		self:removeTemporaryValue("all_damage_convert_percent", p.convertamount)
 		self:removeTemporaryValue("slow_projectiles", p.proj)
 		self:removeParticles(p.particle)
 		return true
 	end,
 	info = function(self, t)
-		local damage = t.getDamage(self, t)
+		local conv = t.getConversion(self, t)
 		local proj = t.getSlow(self, t)
-		return ([[Create a gravity field around you that slows incoming projectiles by %d%% and protects you from all gravity effects.
-		While this spell is active creatures that hit you in melee combat will take %0.2f physical damage and have their knockback resistance reduced by half for two turns.
-		The projectile slowing and damage will scale with your spellpower.]]):format(proj, damDesc(self, DamageType.PHYSICAL, damage))
+		local anti = t.getAnti(self, t)
+		return ([[Create a gravity field around you that converts %d%% of your damage to physical, slows incoming projectiles by %d%%, and protects you from all gravity damage and effects.
+		Additionally, damage dealt by Repulsion Blast has a %d%% chance to reduce the target's knockback resistance by half for two turns.]]):format(conv, proj, anti)
 	end,
 }
 
@@ -219,15 +227,15 @@ newTalent{
 	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
 	cooldown = 12,
 	tactical = { ATTACKAREA = {PHYSICAL = 2}, DISABLE = 2 },
-	range = 10,
-	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
+	range = 6,
+	radius = function(self, t) return 4 end,
 	direct_hit = true,
 	requires_target = true,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t}
 	end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 80, getParadoxSpellpower(self, t)) end,
-	getSlow = function(self, t) return paradoxTalentScale(self, t, 20, 50, 80)/100 end,
+	getSlow = function(self, t) return self:combatTalentLimit(t, 50, 10, 30)/100 end,
 	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 4, 8))) end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
@@ -253,7 +261,7 @@ newTalent{
 		local duration = t.getDuration(self, t)
 		local radius = self:getTalentRadius(t)
 		local slow = t.getSlow(self, t)
-		return ([[Increases local gravity in a radius of %d for %d turns, dealing %0.2f physical damage and slowing the movement speed of all affected targets by %d%%.
+		return ([[Increases local gravity in a radius of %d for %d turns, dealing %0.2f physical (gravity) damage as well as decreasing the global speed of all affected targets by %d%%.
 		The damage done will scale with your Spellpower.]]):format(radius, duration, damDesc(self, DamageType.PHYSICAL, damage), slow*100)
 	end,
 }
diff --git a/game/modules/tome/data/talents/chronomancy/guardian.lua b/game/modules/tome/data/talents/chronomancy/guardian.lua
index 432ccb254a1caf4dee5e9db0725990c0ef0a7c22..4a32d2f7e26f2b99211b5a2ba6016ce82c0c834d 100644
--- a/game/modules/tome/data/talents/chronomancy/guardian.lua
+++ b/game/modules/tome/data/talents/chronomancy/guardian.lua
@@ -31,59 +31,36 @@ newTalent{
 		local damage = t.getDamage(self, t)
 		local inc = t.getPercentInc(self, t)
 		return ([[Increases Physical Power by %d, and increases weapon damage by %d%% when using swords, axes, maces, knives, or bows.
-		You now also use your Magic in place of Strength when equipping weapons, calculating weapon damage, and physical power.
+		You now also use your Magic in place of Strength when equipping weapons and ammo, calculating weapon damage, and physical power.
 		These bonuses override rather than stack with weapon mastery, knife mastery, and bow mastery.]]):
 		format(damage, 100*inc)
 	end,
 }
 
 newTalent{
-	name = "Invigorate",
+	name = "Guardian Unity",
 	type = {"chronomancy/guardian", 2},
 	require = chrono_req2,
 	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
-	cooldown = 24,
-	fixed_cooldown = true,
-	tactical = { HEAL = 1 },
-	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentLimit(self:getTalentLevel(t), 14, 4, 8))) end, -- Limit < 14
-	getPower = function(self, t) return self:combatTalentSpellDamage(t, 10, 50, getParadoxSpellpower(self, t)) end,
-	action = function(self, t)
-		self:setEffect(self.EFF_INVIGORATE, t.getDuration(self,t), {power=t.getPower(self, t)})
-		return true
-	end,
-	info = function(self, t)
-		local power = t.getPower(self, t)
-		local duration = t.getDuration(self, t)
-		return ([[For the next %d turns, you recover %0.1f life per turn and most other talents on cooldown will refresh twice as fast as usual.
-		The amount healed will increase with your Spellpower.]]):format(duration, power)
-	end,
-}
-
-newTalent{
-	name = "Guardian Unity",
-	type = {"chronomancy/guardian", 3},
-	require = chrono_req3,
-	points = 5,
 	mode = "passive",
-	getSplit = function(self, t) return paradoxTalentScale(self, t, 20, 50, 80)/100 end,
+	getSplit = function(self, t) return self:combatTalentLimit(t, 80, 20, 50)/100 end,
 	getDuration = function(self, t) return getExtensionModifier(self, t, 2) end,
-	getLifeTrigger = function(self, t) return self:combatTalentLimit(t, 10, 40, 24)	end,
+	getLifeTrigger = function(self, t) return self:combatTalentLimit(t, 10, 30, 15)	end,
 	remove_on_clone = true,
 	callbackOnHit = function(self, t, cb, src)
 		local split = cb.value * t.getSplit(self, t)
 
 		-- If we already split this turn pass damage to our clone
-		if self.turn_procs.double_edge and self.turn_procs.double_edge ~= self and game.level:hasEntity(self.turn_procs.double_edge) then
+		if self.turn_procs.unity_warden and self.turn_procs.unity_warden ~= self and game.level:hasEntity(self.turn_procs.unity_warden) then
 			split = split/2
 			-- split the damage
-			game:delayedLogDamage(src, self.turn_procs.double_edge, split, ("#STEEL_BLUE#(%d shared)#LAST#"):format(split), nil)
+			game:delayedLogDamage(src, self.turn_procs.unity_warden, split, ("#STEEL_BLUE#(%d shared)#LAST#"):format(split), nil)
 			cb.value = cb.value - split
-			self.turn_procs.double_edge:takeHit(split, src)
+			self.turn_procs.unity_warden:takeHit(split, src)
 		end
 
 		-- Do our split
-		if self.max_life and cb.value >= self.max_life * (t.getLifeTrigger(self, t)/100) and not self.turn_procs.double_edge then
+		if self.max_life and cb.value >= self.max_life * (t.getLifeTrigger(self, t)/100) and not self.turn_procs.unity_warden then
 			-- Look for space first
 			local tx, ty = util.findFreeGrid(self.x, self.y, 5, true, {[Map.ACTOR]=true})
 			if tx and ty then
@@ -110,7 +87,7 @@ newTalent{
 
 				-- split the damage
 				cb.value = cb.value - split
-				self.turn_procs.double_edge = m
+				self.turn_procs.unity_warden = m
 				m:takeHit(split, src)
 				m:setTarget(src or nil)
 				game:delayedLogMessage(self, nil, "guardian_damage", "#STEEL_BLUE##Source# shares damage with %s guardian!", string.his_her(self))
@@ -129,62 +106,106 @@ newTalent{
 		local duration = t.getDuration(self, t)
 		return ([[When a single hit deals more than %d%% of your maximum life another you appears and takes %d%% of the damage as well as %d%% of all other damage you take for the rest of the turn.
 		The clone is out of phase with this reality and deals 50%% less damage but its arrows will pass through friendly targets.  After %d turns it returns to its own timeline.
-		This effect can only occur once per turn and the amount of damage split scales with your Spellpower.]]):format(trigger, split, split/2, duration)
+		This effect can only occur once per turn.]]):format(trigger, split, split/2, duration)
 	end,
 }
 
 newTalent{
-	name = "Breach",
-	type = {"chronomancy/guardian", 4},
-	require = chrono_req4,
+	name = "Warden's Focus", short_name=WARDEN_S_FOCUS,
+	type = {"chronomancy/guardian", 3},
+	require = chrono_req3,
 	points = 5,
-	cooldown = 8,
-	paradox = function (self, t) return getParadoxCost(self, t, 15) end,
-	tactical = { ATTACK = {weapon = 2}, DISABLE = 3 },
+	cooldown = 6,
+	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
+	tactical = { BUFF = 2 },
+	direct_hit = true,
 	requires_target = true,
-	range = function(self, t)
-		if self:hasArcheryWeapon("bow") then return util.getval(archery_range, self, t) end
-		return 1
-	end,
-	is_melee = function(self, t) return not self:hasArcheryWeapon("bow") end,
-	speed = function(self, t) return self:hasArcheryWeapon("bow") and "archery" or "weapon" end,
-	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
-	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 3, 7))) end,
-	on_pre_use = function(self, t, silent) if self:attr("disarmed") then if not silent then game.logPlayer(self, "You require a weapon to use this talent.") end return false end return true end,
-	archery_onhit = function(self, t, target, x, y)
-		target:setEffect(target.EFF_BREACH, t.getDuration(self, t), {})
+	range = 10,
+	target = function (self, t)
+		return {type="hit", range=self:getTalentRange(t), talent=t}
 	end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 8, 16))) end,
+	getAttack = function(self, t) return self:combatTalentSpellDamage(t, 10, 100, getParadoxSpellpower(self, t)) end,
+	getCrit = function(self, t) return self:combatTalentSpellDamage(t, 5, 50, getParadoxSpellpower(self, t)) end,
 	action = function(self, t)
-		local mainhand, offhand = self:hasDualWeapon()
-
-		if self:hasArcheryWeapon("bow") then
-			-- Ranged attack
-			local targets = self:archeryAcquireTargets({type="bolt"}, {one_shot=true, no_energy = true})
-			if not targets then return end
-			self:archeryShoot(targets, t, {type="bolt"}, {mult=t.getDamage(self, t)})
-		elseif mainhand then
-			-- Melee attack
-			local tg = {type="hit", range=self:getTalentRange(t), talent=t}
-			local x, y, target = self:getTarget(tg)
-			if not target or not self:canProject(tg, x, y) then return nil end
-			local hitted = self:attackTarget(target, nil, t.getDamage(self, t), true)
-
-			if hitted then
-				target:setEffect(target.EFF_BREACH, t.getDuration(self, t), {apply_power=getParadoxSpellpower(self, t)})
-			end
-		else
-			game.logPlayer(self, "You cannot use Breach without an appropriate weapon!")
-			return nil
-		end
-
+		local tg = self:getTalentTarget(t)
+		local tx, ty = self:getTarget(tg)
+		if not tx or not ty then return nil end
+		local _ _, tx, ty = self:canProject(tg, tx, ty)
+		local target = game.level.map(tx, ty, Map.ACTOR)
+		if not target then return end
+		
+		self:setEffect(self.EFF_WARDEN_S_FOCUS, t.getDuration(self, t), {target=target, atk=t.getAttack(self, t), crit=t.getCrit(self, t)})
+		target:setEffect(target.EFF_WARDEN_S_TARGET, 10, {src=self, atk=t.getAttack(self, t), crit=t.getCrit(self, t)})
+		
+		game:playSoundNear(self, "talents/dispel")
+		
 		return true
 	end,
 	info = function(self, t)
 		local duration = t.getDuration(self, t)
-		local damage = t.getDamage(self, t) * 100
-		return ([[Attack the target with either your bow or melee weapons for %d%% damage.
-		If the attack hits you'll breach the target's immunities, reducing armor hardiness, stun, pin, blindness, and confusion immunity by 50%% for %d turns.
-		Breach chance scales with your Spellpower.]])
-		:format(damage, duration)
+		local atk = t.getAttack(self, t)
+		local crit = t.getCrit(self, t)
+		return ([[For the next %d turns random targeting, such as from Blink Blade and Warden's Call, will focus on this target.
+		Additionally you gain +%d accuracy and +%d%% critical hit rate when attacking this target.
+		The accuracy and critical hit rate bonuses will scale with your Spellpower.]])
+		:format(duration, atk, crit)
 	end
 }
+
+newTalent{
+	name = "Vigilance",
+	type = {"chronomancy/guardian", 4},
+	require = chrono_req4,
+	points = 5,
+	mode = "passive",
+	getSense = function(self, t) return self:combatTalentStatDamage(t, "mag", 5, 25) end,
+	getPower = function(self, t) return self:combatTalentLimit(t, 40, 10, 30) end, -- Limit < 40%end,
+	passives = function(self, t, p)
+		self:talentTemporaryValue(p, "see_stealth", t.getSense(self, t))
+		self:talentTemporaryValue(p, "see_invisible", t.getSense(self, t))
+	end,
+	callbackOnStatChange = function(self, t, stat, v)
+		if stat == self.STAT_MAG then
+			self:updateTalentPassives(t)
+		end
+	end,
+	callbackOnActBase = function(self, t)
+		if rng.percent(t.getPower(self, t)) then
+			local effs = {}
+			-- Go through all spell effects
+			for eff_id, p in pairs(self.tmp) do
+				local e = self.tempeffect_def[eff_id]
+				if e.type ~= "other" and e.status == "detrimental" and e.subtype ~= "cross tier" then
+					effs[#effs+1] = {"effect", eff_id}
+				end
+			end
+			
+			if #effs > 0 then
+				local eff = rng.tableRemove(effs)
+				if eff[1] == "effect" then
+					self:removeEffect(eff[2])
+					game.logSeen(self, "#ORCHID#%s has recovered!#LAST#", self.name:capitalize())
+				end
+			end
+		end
+	end,
+	callbackOnTakeDamage = function(self, t, src, x, y, type, dam, tmp)
+		local eff = self:hasEffect(self.EFF_WARDEN_S_FOCUS)
+		if eff and dam > 0 and eff.target ~= src and src ~= self then
+			-- Reduce damage
+			local reduction = dam * self:callTalent(self.T_VIGILANCE, "getPower")/100
+			dam = dam -  reduction
+			game:delayedLogDamage(src, self, 0, ("%s(%d vigilance)#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", reduction), false)
+		end
+		return {dam=dam}
+	end,
+	info = function(self, t)
+		local sense = t.getSense(self, t)
+		local power = t.getPower(self, t)
+		return ([[Improves your capacity to see invisible foes by +%d and to see through stealth by +%d.  You also have a %d%% chance to recover from a single negative status effect each turn.
+		While Warden's Focus is active you reduce incoming damage from all targets other than your focus target by %d%%.
+		Sense abilities will scale with your Magic stat.]]):
+		format(sense, sense, power, power)
+	end,
+}
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/chronomancy/matter.lua b/game/modules/tome/data/talents/chronomancy/matter.lua
index bbab32e1888054b686849ee60825f77de99b8b9b..c07cb854e644dc748a4b16a4988a1006cc70ab44 100644
--- a/game/modules/tome/data/talents/chronomancy/matter.lua
+++ b/game/modules/tome/data/talents/chronomancy/matter.lua
@@ -17,6 +17,8 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
+local Object = require "mod.class.Object"
+
 newTalent{
 	name = "Dust to Dust",
 	type = {"chronomancy/matter",1},
@@ -29,171 +31,282 @@ newTalent{
 	direct_hit = true,
 	reflectable = true,
 	requires_target = true,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 1.25, 3.25)) end,
 	target = function(self, t)
-		return {type="beam", range=self:getTalentRange(t), talent=t}
+		return {type="beam", range=self:getTalentRange(t), talent=t, nowarning=true, selffire=false}
 	end,
+	getAshes = function(self, t) return {type="ball", range=0, radius=self:getTalentRadius(t), selffire=false} end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 230, getParadoxSpellpower(self, t)) end,
 	action = function(self, t)
+		-- Check for digs first
+		local digs = self:isTalentActive(self.T_DISINTEGRATION) and self:callTalent(self.T_DISINTEGRATION, "getDigs")
 		local tg = self:getTalentTarget(t)
-		local x, y = self:getTarget(tg)
+		
+		-- Just for targeting change to pass terrain
+		if digs then tg.pass_terrain = true end
+		local x, y, target = self:getTarget(tg)
 		if not x or not y then return nil end
-		self:project(tg, x, y, DamageType.MATTER, self:spellCrit(t.getDamage(self, t)))
-		local _ _, _, _, x, y = self:canProject(tg, x, y)
-		game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(x-self.x), math.abs(y-self.y)), "matter_beam", {tx=x-self.x, ty=y-self.y})
-		game:playSoundNear(self, "talents/arcane")
+		
+		-- Change back pass terrain
+		tg.pass_terrain = nil
+		
+		
+		-- Ashes to Ashes
+		if target and target == self then
+			tg = t.getAshes(self, t)
+			-- We do our digs seperatly and first so we can damage stuff on the other side
+			if digs then
+				game.level.map:addEffect(self,
+					self.x, self.y, 3,
+					DamageType.DIG, digs,
+					tg.radius,
+					5, nil,
+					nil,
+					function(e)
+						e.x = e.src.x
+						e.y = e.src.y
+						return true
+					end,
+					tg.selffire
+				)
+			end
+			game.level.map:addEffect(self,
+				self.x, self.y, 3,
+				DamageType.WARP, self:spellCrit(t.getDamage(self, t)/3),
+				tg.radius,
+				5, nil,
+				engine.MapEffect.new{color_br=180, color_bg=100, color_bb=255, effect_shader="shader_images/magic_effect.png"},
+				function(e)
+					e.x = e.src.x
+					e.y = e.src.y
+					return true
+				end,
+				tg.selffire
+			)
+			
+			game:playSoundNear(self, "talents/cloud")
+		else
+			-- and Dust to Dust
+			if digs then for i = 1, digs do self:project(tg, x, y, DamageType.DIG, 1) end end
+		
+			self:project(tg, x, y, DamageType.WARP, self:spellCrit(t.getDamage(self, t)))
+			local _ _, _, _, x, y = self:canProject(tg, x, y)
+			game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(x-self.x), math.abs(y-self.y)), "matter_beam", {tx=x-self.x, ty=y-self.y})
+			game:playSoundNear(self, "talents/arcane")
+		end
+		
 		return true
 	end,
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
-		return ([[Fires a beam that turns matter into dust, inflicting %0.2f temporal damage and %0.2f physical damage.
+		local radius = self:getTalentRadius(t)
+		return ([[Fires a beam that turns matter into dust, inflicting %0.2f temporal damage and %0.2f physical (warp) damage.
+		Alternatively you may target yourself, creating a field of radius %d around you that will inflict the damage over three turns.
 		The damage will scale with your Spellpower.]]):
-		format(damDesc(self, DamageType.TEMPORAL, damage / 2), damDesc(self, DamageType.PHYSICAL, damage / 2))
+		format(damDesc(self, DamageType.TEMPORAL, damage / 2), damDesc(self, DamageType.PHYSICAL, damage / 2), radius)
 	end,
 }
 
 newTalent{
-	name = "Carbon Spikes",
-	type = {"chronomancy/matter", 2},
-	require = chrono_req2, no_sustain_autoreset = true,
+	name = "Matter Weaving",
+	type = {"chronomancy/matter",2},
+	require = chrono_req2,
 	points = 5,
+	sustain_paradox = 24,
 	mode = "sustained",
-	sustain_paradox = 20,
-	cooldown = 12,
-	tactical = { BUFF =2, DEFEND = 2 },
-	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 1, 150, getParadoxSpellpower(self, t)) end,
-	getArmor = function(self, t) return math.ceil(self:combatTalentSpellDamage(t, 20, 50, getParadoxSpellpower(self, t))) end,
-	callbackOnActBase = function(self, t)
-		local maxspikes = t.getArmor(self, t)
-		if self.carbon_armor < maxspikes then
-			self.carbon_armor = self.carbon_armor + 1
-		end
-	end,
-	do_carbonLoss = function(self, t)
-		if self.carbon_armor >= 1 then
-			self.carbon_armor = self.carbon_armor - 1
-		else
-			-- Deactivate without loosing energy
-			self:forceUseTalent(self.T_CARBON_SPIKES, {ignore_energy=true})
-		end
-	end,
+	cooldown = 10,
+	tactical = { BUFF = 2 },
+	getStunResist = function(self, t) return self:combatTalentLimit(t, 1, 0.15, 0.50) end, -- Limit <100%
+	getCutResist = function(self, t) return math.min(1, self:combatTalentScale(t, 0.2, 1)) end, -- Limit <100%
+	getCap = function(self, t) return 100 - self:combatTalentLimit(t, 50, 10, 40) end, -- Limit < 50%
 	activate = function(self, t)
-		local power = t.getArmor(self, t)
-		self.carbon_armor = power
-		game:playSoundNear(self, "talents/spell_generic")
-		return {
-			armor = self:addTemporaryValue("carbon_spikes", power),
-			onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.BLEED]=t.getDamageOnMeleeHit(self, t)}),			
+		game:playSoundNear(self, "talents/earth")
+		
+		local ret = {
+			stun = self:addTemporaryValue("stun_immune", t.getStunResist(self, t)),
+			cut = self:addTemporaryValue("cut_immune", t.getCutResist(self, t)),
+			cap = self:addTemporaryValue("flat_damage_cap", {all=t.getCap(self, t)}),
 		}
+				if not self:addShaderAura("stone_skin", "crystalineaura", {time_factor=1500, spikeOffset=0.123123, spikeLength=0.9, spikeWidth=3, growthSpeed=2, color={100/255, 100/255, 100/255}}, "particles_images/spikes.png") then
+			ret.particle = self:addParticles(Particles.new("stone_skin", 1))
+		end
+		return ret
 	end,
 	deactivate = function(self, t, p)
-		self:removeTemporaryValue("carbon_spikes", p.armor)
-		self:removeTemporaryValue("on_melee_hit", p.onhit)
-		self.carbon_armor = nil
+		self:removeShaderAura("stone_skin")
+		self:removeParticles(p.particle)
+		self:removeTemporaryValue("stun_immune", p.stun)
+		self:removeTemporaryValue("cut_immune", p.cut)
+		self:removeTemporaryValue("flat_damage_cap", p.cap)
 		return true
 	end,
 	info = function(self, t)
-		local damage = t.getDamageOnMeleeHit(self, t)
-		local armor = t.getArmor(self, t)
-		return ([[Fragile spikes of carbon protrude from your flesh, clothing, and armor, increasing your armor rating by %d and inflicting %0.2f bleed damage over six turns on attackers.   Each time you're struck, the armor increase will be reduced by 1.  Each turn the spell will regenerate 1 armor up to its starting value.
-		If the armor increase from the spell ever falls below 1, the sustain will deactivate and the effect will end.
-		The armor and bleed damage will increase with your Spellpower.]]):
-		format(armor, damDesc(self, DamageType.PHYSICAL, damage))
+		local cap = t.getCap(self, t)
+		local stun = t.getStunResist(self, t) * 100
+		local cut = t.getCutResist(self, t) * 100
+		return ([[Weave matter into your flesh, becoming incredibly resilient to damage.  While active you can never take a blow that deals more than %d%% of your maximum life.
+		Additionally you gain %d%% resistance to stunning and %d%% resistance to cuts.]]):
+		format(cap, stun, cut)
 	end,
 }
 
 newTalent{
-	name = "Destabilize",
-	type = {"chronomancy/matter", 3},
+	name = "Materialize Barrier",
+	type = {"chronomancy/matter",3},
 	require = chrono_req3,
 	points = 5,
+	paradox = function (self, t) return getParadoxCost(self, t, 15) end,
 	cooldown = 10,
-	paradox = function (self, t) return getParadoxCost(self, t, 30) end,
+	tactical = { DISABLE = 2 },
 	range = 10,
-	tactical = { ATTACK = 2 },
-	requires_target = true,
 	direct_hit = true,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 60, getParadoxSpellpower(self, t)) end,
-	getExplosion = function(self, t) return self:combatTalentSpellDamage(t, 20, 230, getParadoxSpellpower(self, t)) end,
+	requires_target = true,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 1.25, 3.25)) end,
+	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 220, getParadoxSpellpower(self, t)) end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 4, 6))) end,
+	getLength = function(self, t) return 1 + math.floor(self:combatTalentScale(t, 3, 7)/2)*2 end,
+	target = function(self, t)
+		local halflength = math.floor(t.getLength(self,t)/2)
+		local block = function(_, lx, ly)
+			return game.level.map:checkAllEntities(lx, ly, "block_move")
+		end
+		return {type="wall", range=self:getTalentRange(t), halflength=halflength, talent=t, halfmax_spots=halflength+1, block_radius=block}
+	end,
 	action = function(self, t)
-		local tg = {type="hit", range=self:getTalentRange(t), talent=t}
+		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
 		if not x or not y then return nil end
-		self:project(tg, x, y, function(px, py)
-			local target = game.level.map(px, py, Map.ACTOR)
-			if not target then return end
-			target:setEffect(target.EFF_TEMPORAL_DESTABILIZATION, 10, {src=self, dam=t.getDamage(self, t), explosion=self:spellCrit(t.getExplosion(self, t))})
-			game.level.map:particleEmitter(target.x, target.y, 1, "entropythrust")
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		if game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move") then return nil end
+
+		self:project(tg, x, y, function(px, py, tg, self)
+			local oe = game.level.map(px, py, Map.TERRAIN)
+			if not oe or oe.special then return end
+			if not oe or oe:attr("temporary") or game.level.map:checkAllEntities(px, py, "block_move") then return end
+				local e = Object.new{
+					old_feat = oe,
+					name = "stone wall", image = "terrain/rocky_mountain.png",
+					display = '#', color_r=255, color_g=255, color_b=255, back_color=colors.GREY,
+					shader = "shadow_simulacrum",
+					shader_args = { color = {0.6, 0.6, 0.2}, base = 0.9, time_factor = 1500 },
+					desc = "a summoned wall of stone",
+					type = "wall", --subtype = "floor",
+					always_remember = true,
+					can_pass = {pass_wall=1},
+					does_block_move = true,
+					show_tooltip = true,
+					block_move = true,
+					block_sight = true,
+					temporary = t.getDuration(self, t),
+					x = px, y = py,
+					canAct = false,
+					act = function(self)
+						self:useEnergy()
+						self.temporary = self.temporary - 1
+						if self.temporary <= 0 then
+							game.level.map(self.x, self.y, engine.Map.TERRAIN, self.old_feat)
+							game.nicer_tiles:updateAround(game.level, self.x, self.y)
+							game.level:removeEntity(self)
+							game.level.map:scheduleRedisplay()
+						end
+					end,
+					dig = function(src, x, y, old)
+						-- Explode!
+						local self = game.level.map(x, y, engine.Map.TERRAIN)
+						local t = self.summoner:getTalentFromId(self.summoner.T_MATERIALIZE_BARRIER)
+						local tg = {type="ball", range=0, radius = self.summoner:getTalentRadius(t), talent=t, x=self.x, y=self.y}
+						self.summoner.__project_source = self
+						self.summoner:project(tg, self.x, self.y, engine.DamageType.BLEED, self.summoner:spellCrit(t.getDamage(self.summoner, t)))
+						self.summoner.__project_source = nil
+						game.level.map:particleEmitter(x, y, tg.radius, "ball_earth", {radius=tg.radius})
+						
+						game.level:removeEntity(old)
+						game.level.map:scheduleRedisplay()
+						return nil, old.old_feat
+					end,
+					summoner_gain_exp = true,
+					summoner = self,
+				}
+			e.tooltip = mod.class.Grid.tooltip
+			game.level:addEntity(e)
+			game.level.map(px, py, Map.TERRAIN, e)
 		end)
-		game:playSoundNear(self, "talents/cloud")
+		
+		game:playSoundNear(self, "talents/earth")
+		
 		return true
 	end,
 	info = function(self, t)
+		local length = t.getLength(self, t)
+		local duration = t.getDuration(self, t)
 		local damage = t.getDamage(self, t)
-		local explosion = t.getExplosion(self, t)
-		return ([[Destabilizes the target, inflicting %0.2f temporal damage per turn for 10 turns.  If the target dies while destabilized, it will explode, doing %0.2f temporal damage and %0.2f physical damage in a radius of 4.
-		If the target dies while also under the effects of continuum destabilization, all explosion damage will be done as temporal damage.
-		The damage will scale with your Spellpower.]]):
-		format(damDesc(self, DamageType.TEMPORAL, damage), damDesc(self, DamageType.TEMPORAL, explosion/2), damDesc(self, DamageType.PHYSICAL, explosion/2))
+		local radius = self:getTalentRadius(t)
+		return ([[Create a tightly bound matter wall of up to a length of %d that lasts %d turns.
+		If any part of this wall is dug out it will explode, causing targets in a radius of %d to bleed for %0.2f physical damage over six turns.]])
+		:format(length, duration, radius, damDesc(self, DamageType.PHYSICAL, damage))
 	end,
 }
 
 newTalent{
-	name = "Quantum Spike",
-	type = {"chronomancy/matter", 4},
+	name = "Disintegration",
+	type = {"chronomancy/matter",4},
 	require = chrono_req4,
 	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 40) end,
-	cooldown = 4,
-	tactical = { ATTACK = {TEMPORAL = 1, PHYSICAL = 1} },
-	range = 10,
-	direct_hit = true,
-	reflectable = true,
-	requires_target = true,
-	target = function(self, t)
-		return {type="hit", range=self:getTalentRange(t), talent=t}
-	end,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 30, 300, getParadoxSpellpower(self, t)) end,
-	action = function(self, t)
-		local tg = self:getTalentTarget(t)
-		local x, y, target = self:getTarget(tg)
-		if not x or not y then return nil end
-		
-		-- bonus damage on targets with temporal destabilization
-		local damage = t.getDamage(self, t)
-		if target then 
-			if target:hasEffect(target.EFF_TEMPORAL_DESTABILIZATION) or target:hasEffect(target.EFF_CONTINUUM_DESTABILIZATION) then
-				damage = damage * 1.5
-			end
-		end
-		
+	sustain_paradox = 24,
+	mode = "sustained",
+	cooldown = 10,
+	tactical = { BUFF = 2 },
+	getDigs = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5, "log")) end,
+	getChance = function(self, t) return self:combatTalentLimit(t, 50, 10, 40) end, -- Limit < 50%end,
+	doStrip = function(self, t, target, type)
+		local what = type == "PHYSICAL" and "physical" or "magical"
+		local p = self:isTalentActive(self.T_DISINTEGRATION)
 		
-		self:project(tg, x, y, DamageType.MATTER, self:spellCrit(damage))
-		game:playSoundNear(self, "talents/arcane")
+		if what == "physical" and p.physical[target] then return end
+		if what == "magical" and p.magical[target] then return end
 		
-		-- Try to insta-kill
-		if target then
-			if target:checkHit(self:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
-				-- KILL IT !
-				game.logSeen(target, "%s has been pulled apart at a molecular level!", target.name:capitalize())
-				target:die(self)
-			elseif target.life > 0 and target.life < target.max_life * 0.2 then
-				game.logSeen(target, "%s resists the quantum spike!", target.name:capitalize())
+		if rng.percent(t.getChance(self, t)) then
+			local effs = {}
+			-- Go through all spell effects
+			for eff_id, p in pairs(target.tmp) do
+				local e = target.tempeffect_def[eff_id]
+				if e.type == what and e.status == "beneficial" then
+					effs[#effs+1] = {"effect", eff_id}
+				end
+			end
+	
+			if #effs > 0 then
+				local eff = rng.tableRemove(effs)
+				if eff[1] == "effect" then
+					target:removeEffect(eff[2])
+					game.logSeen(self, "#CRIMSON#%s's beneficial effect was stripped!#LAST#", target.name:capitalize())
+					if what == "physical" then p.physical[target] = true end
+					if what == "magical" then p.magical[target] = true end
+				end
 			end
 		end
-		
-		-- if we kill it use teleport particles for larger effect radius
-		if target and target.dead then
-			game.level.map:particleEmitter(x, y, 1, "teleport")
-		else
-			game.level.map:particleEmitter(x, y, 1, "entropythrust")
+	end,
+	callbackOnActBase = function(self, t)
+		-- reset our targets
+		local p = self:isTalentActive(self.T_DISINTEGRATION)
+		if p then
+			p.physical = {}
+			p.magical = {}
 		end
-		
+	end,
+	activate = function(self, t)
+		return { physical = {}, magical ={}
+		}
+	end,
+	deactivate = function(self, t, p)
 		return true
 	end,
 	info = function(self, t)
-		local damage = t.getDamage(self, t)
-		return ([[Attempts to pull the target apart at a molecular level, inflicting %0.2f temporal damage and %0.2f physical damage.  If the target ends up with low enough life (<20%%), it might be instantly killed.
-		Quantum Spike deals 50%% additional damage to targets affected by temporal destabilization and/or continuum destabilization.
-		The damage will scale with your Spellpower.]]):format(damDesc(self, DamageType.TEMPORAL, damage/2), damDesc(self, DamageType.PHYSICAL, damage/2))
+		local digs = t.getDigs(self, t)
+		local chance = t.getChance(self, t)
+		return ([[While active your physical and temporal damage has a %d%% chance to remove one beneficial physical or magical effect (respectively) from targets you hit.
+		Only one physical and one magical effect may be removed per turn from each target.
+		Additionally your Dust to Dust spell now digs up to %d tiles into walls.]]):
+		format(chance, digs)
 	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/chronomancy/other.lua b/game/modules/tome/data/talents/chronomancy/other.lua
index 6efa44884742b6ec50104d469e666c0ea81aa7ed..73ed8373ed628c96b711148fd0d13bfb3388033b 100644
--- a/game/modules/tome/data/talents/chronomancy/other.lua
+++ b/game/modules/tome/data/talents/chronomancy/other.lua
@@ -31,7 +31,11 @@ end
 -- Paradox cost (regulates the cost of paradox talents)
 getParadoxCost = function (self, t, value)
 	local pm = getParadoxModifier(self)
-	return value * pm
+	local multi = 1
+	if self:attr("paradox_cost_multiplier") then
+		multi = 1 - self:attr("paradox_cost_multiplier")
+	end
+	return (value * pm) * multi
 end
 
 -- Paradox Spellpower (regulates spellpower for chronomancy)
@@ -49,17 +53,6 @@ getParadoxSpellpower = function(self, t, mod, add)
 	return spellpower
 end
 
--- Paradox Talent scaling based on Spellpower (thanks grayswandir)
-paradoxTalentScale = function(self, t, low, high, limit)
-        local low_power = 50
-        local high_power = 150
-        return self:combatLimit(
-                self:combatTalentSpellDamage(t, low_power, high_power, getParadoxSpellpower(self, t)),
-                limit,
-                low, low_power,
-                high, high_power)
-end
-
 -- Extension Spellbinding
 getExtensionModifier = function(self, t, value)
 	local mod = 1
@@ -88,43 +81,88 @@ doWardenPreUse = function(self, weapon, silent)
 end
 
 -- Swaps weapons if needed
-doWardenWeaponSwap = function(self, t, dam, type)
+doWardenWeaponSwap = function(self, t, dam, type, silent)
 	local swap = false
 	local dam = dam or 0
 	local warden_weapon
 
-	if t.type[1]:find("^chronomancy/blade") or type == "blade" then
+	if type == "blade" then
 		local mainhand, offhand = self:hasDualWeapon()
 		if not mainhand then
 			swap = true
 			warden_weapon = "blade"
 		end
 	end
-	if t.type[1]:find("^chronomancy/bow") or type == "bow" then
+	if type == "bow" then
 		if not self:hasArcheryWeapon("bow") then
 			swap = true
 			warden_weapon = "bow"
 		end
 	end
+	
 	if swap == true then
 		local old_inv_access = self.no_inventory_access				-- Make sure clones can swap
 		self.no_inventory_access = nil
-		self:quickSwitchWeapons(true, "warden")
+		self:quickSwitchWeapons(true, "warden", silent)
 		self.no_inventory_access = old_inv_access
-
-		if self:knowTalent(self.T_BLENDED_THREADS) then
-			if not self.turn_procs.blended_threads then
-				self.turn_procs.blended_threads = warden_weapon
-			end
-			if self.turn_procs.blended_threads == warden_weapon then
-				dam = dam * (1 + self:callTalent(self.T_BLENDED_THREADS, "getPercent"))
+		
+		if t and (t.type[1]:find("^chronomancy/blade") or t.type[1]:find("^chronomancy/bow")) then
+			if self:knowTalent(self.T_BLENDED_THREADS) then
+				if not self.turn_procs.blended_threads then
+					self.turn_procs.blended_threads = warden_weapon
+				end
+				if self.turn_procs.blended_threads == warden_weapon then
+					dam = dam * (1 + self:callTalent(self.T_BLENDED_THREADS, "getPercent"))
+				end
 			end
 		end
 	end
-	return dam, swap
+	
+	return swap, dam
+end
+
+-- Target helper function for focus fire
+checkWardenFocus = function(self)
+	local target
+	local eff = self:hasEffect(self.EFF_WARDEN_S_FOCUS)
+	if eff then
+		target = eff.target
+	end
+	return target
 end
 
 -- Spell functions
+randomWarpEffect = function(self, t, target)
+	local eff = rng.range(1, 4)
+	local power = getParadoxSpellpower(self, t)
+	-- Pull random effect
+	if eff == 1 then
+		if target:canBe("stun") then
+			target:setEffect(target.EFF_STUNNED, t.getDuration(self, t), {apply_power=power})
+		else
+			game.logSeen(target, "%s resists the stun!", target.name:capitalize())
+		end
+	elseif eff == 2 then
+		if target:canBe("blind") then
+			target:setEffect(target.EFF_BLINDED, t.getDuration(self, t), {apply_power=power})
+		else
+			game.logSeen(target, "%s resists the blindness!", target.name:capitalize())
+		end
+	elseif eff == 3 then
+		if target:canBe("pin") then
+			target:setEffect(target.EFF_PINNED, t.getDuration(self, t), {apply_power=power})
+		else
+			game.logSeen(target, "%s resists the pin!", target.name:capitalize())
+		end
+	elseif eff == 4 then
+		if target:canBe("confusion") then
+			target:setEffect(target.EFF_CONFUSED, t.getDuration(self, t), {power=50, apply_power=power})
+		else
+			game.logSeen(target, "%s resists the confusion!", target.name:capitalize())
+		end
+	end
+end
+
 makeParadoxClone = function(self, target, duration)
 	local m = target:cloneFull{
 		shader = "shadow_simulacrum",
@@ -185,18 +223,16 @@ makeParadoxClone = function(self, target, duration)
 	end
 
 	-- remove timed effects
-	local effs = {}
-	for eff_id, p in pairs(m.tmp) do
-		local e = m.tempeffect_def[eff_id]
-		effs[#effs+1] = {"effect", eff_id}
-	end
-
-	while #effs > 0 do
-		local eff = rng.tableRemove(effs)
-		if eff[1] == "effect" then
-			m:removeEffect(eff[2])
+	m:removeTimedEffectsOnClone()
+	
+	-- reset folds for our Warden clones
+	for tid, cd in pairs(m.talents_cd) do
+		local t = m:getTalentFromId(tid)
+		if t.type[1]:find("^chronomancy/manifold") and m:knowTalent(tid) then
+			m:alterTalentCoolingdown(t, -cd)
 		end
 	end
+	
 	return m
 end
 
@@ -224,8 +260,11 @@ newTalent{
 		if self.preferred_paradox then self.preferred_paradox = nil end
 	end,
 	getDuration = function(self, t)
-		local power = math.floor(self:combatSpellpower()/10)
-		return math.max(20 - power, 10)
+		local duration = 20
+		if self:knowTalent(self.T_SPACETIME_STABILITY) then
+			duration = duration - self:callTalent(self.T_SPACETIME_STABILITY, "getTuningAdjustment")
+		end
+		return math.max(duration, 10)
 	end,
 	action = function(self, t)
 		local function getQuantity(title, prompt, default, min, max)
@@ -267,7 +306,6 @@ newTalent{
 		local after_will, will_modifier, sustain_modifier = self:getModifiedParadox()
 		local anomaly = self:paradoxFailChance()
 		return ([[Use to set your preferred Paradox.  While resting or waiting you'll adjust your Paradox towards this number over %d turns.
-		The time it takes you to adjust your Paradox scales down with your Spellpower to a minimum of 10 turns.
 
 		Preferred Paradox          :  %d
 		Spellpower for Chronomancy :  %d
@@ -279,45 +317,6 @@ newTalent{
 }
 
 -- Talents from older versions to keep save files compatable
-newTalent{
-	name = "Stop",
-	type = {"chronomancy/other",1},
-	require = chrono_req1,
-	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
-	cooldown = 12,
-	tactical = { ATTACKAREA = 1, DISABLE = 3 },
-	range = 6,
-	radius = function(self, t) return math.floor(self:combatTalentScale(t, 1.3, 2.7)) end,
-	direct_hit = true,
-	requires_target = true,
-	target = function(self, t)
-		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=self:spellFriendlyFire(), talent=t}
-	end,
-	getDuration = function(self, t) return math.ceil(self:combatTalentScale(self:getTalentLevel(t), 2.3, 4.3)) end,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 170, getParadoxSpellpower(self, t)) end,
-	action = function(self, t)
-		local tg = self:getTalentTarget(t)
-		local x, y = self:getTarget(tg)
-		if not x or not y then return nil end
-		local _ _, _, _, x, y = self:canProject(tg, x, y)
-		local grids = self:project(tg, x, y, DamageType.STOP, t.getDuration(self, t))
-		self:project(tg, x, y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t)))
-
-		game.level.map:particleEmitter(x, y, tg.radius, "temporal_flash", {radius=tg.radius, tx=x, ty=y})
-		game:playSoundNear(self, "talents/tidalwave")
-		return true
-	end,
-	info = function(self, t)
-		local damage = t.getDamage(self, t)
-		local radius = self:getTalentRadius(t)
-		local duration = t.getDuration(self, t)
-		return ([[Inflicts %0.2f temporal damage, and attempts to stun all creatures in a radius %d ball for %d turns.
-		The damage will scale with your Spellpower.]]):
-		format(damage, radius, duration)
-	end,
-}
-
 newTalent{
 	name = "Slow",
 	type = {"chronomancy/other", 1},
@@ -388,37 +387,6 @@ newTalent{
 	end,
 }
 
-newTalent{
-	name = "Static History",
-	type = {"chronomancy/other", 1},
-	require = chrono_req1,
-	points = 5,
-	message = "@Source@ rearranges history.",
-	cooldown = 24,
-	tactical = { PARADOX = 2 },
-	getDuration = function(self, t)
-		local duration = math.floor(self:combatTalentScale(t, 1.5, 3.5))
-		if self:knowTalent(self.T_PARADOX_MASTERY) then
-			duration = duration + self:callTalent(self.T_PARADOX_MASTERY, "stabilityDuration")
-		end
-		return duration
-	end,
-	getReduction = function(self, t) return self:combatTalentSpellDamage(t, 20, 200) end,
-	action = function(self, t)
-		self:incParadox (- t.getReduction(self, t))
-		game:playSoundNear(self, "talents/spell_generic")
-		self:setEffect(self.EFF_SPACETIME_STABILITY, t.getDuration(self, t), {})
-		return true
-	end,
-	info = function(self, t)
-		local reduction = t.getReduction(self, t)
-		local duration = t.getDuration(self, t)
-		return ([[By slightly reorganizing history, you reduce your Paradox by %d and temporarily stabilize the timeline; this allows chronomancy to be used without chance of failure for %d turns (backfires and anomalies may still occur).
-		The paradox reduction will increase with your Spellpower.]]):
-		format(reduction, duration)
-	end,
-}
-
 newTalent{
 	name = "Quantum Feed",
 	type = {"chronomancy/other", 1},
@@ -574,7 +542,7 @@ newTalent{
 	range = 2,
 	requires_target = true,
 	no_npc_use = true,
-	getDuration = function(self, t)	return math.floor(self:combatTalentLimit(self:getTalentLevel(t), 50, 4, 8)) end, -- Limit <50
+	getDuration = function(self, t)	return math.floor(self:combatTalentLimit(t, 50, 4, 8)) end, -- Limit <50
 	getModifier = function(self, t) return rng.range(t.getDuration(self,t)*2, t.getDuration(self, t)*4) end,
 	action = function (self, t)
 		if checkTimeline(self) == true then
@@ -830,23 +798,6 @@ newTalent{
 	end,
 }
 
-newTalent{
-	name = "Paradox Mastery",
-	type = {"chronomancy/other", 1},
-	mode = "passive",
-	points = 5,
-	-- Static history bonus handled in timetravel.lua, backfire calcs performed by _M:getModifiedParadox function in mod\class\Actor.lua
-	WilMult = function(self, t) return self:combatTalentScale(t, 0.15, 0.5) end,
-	stabilityDuration = function(self, t) return math.floor(self:combatTalentScale(t, 0.4, 2.7, "log")) end,  --This is still used by an older talent, leave it here for backwards compatability
-	passives = function(self, t, p)
-		self:talentTemporaryValue(p, "paradox_will_mutli", t.WilMult(self, t))
-	end,
-	info = function(self, t)
-		return ([[You've learned to focus your control over the spacetime continuum, and quell anomalous effects.  Increases your effective Willpower for anomaly calculations by %d%%.]]):
-		format(t.WilMult(self, t) * 100)
-	end,
-}
-
 newTalent{
 	name = "Damage Smearing",
 	type = {"chronomancy/other", 1},
@@ -883,59 +834,23 @@ newTalent{
 }
 
 newTalent{
-	name = "Banish",
+	name = "Phase Shift",
 	type = {"chronomancy/other", 1},
+	require = chrono_req2,
 	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
-	cooldown = 10,
-	tactical = { ESCAPE = 2 },
-	range = 0,
-	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 5.5)) end,
-	getTeleport = function(self, t) return math.floor(self:combatTalentScale(self:getTalentLevel(t), 8, 16)) end,
-	target = function(self, t)
-		return {type="ball", range=0, radius=self:getTalentRadius(t), selffire=false, talent=t}
-	end,
-	requires_target = true,
-	direct_hit = true,
+	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
+	cooldown = 24,
+	tactical = { DEFEND = 2 },
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentLimit(t, 25, 3, 7, true))) end,
 	action = function(self, t)
-		local tg = self:getTalentTarget(t)
-		local hit = false
-
-		self:project(tg, self.x, self.y, function(px, py)
-			local target = game.level.map(px, py, Map.ACTOR)
-			if not target or target == self then return end
-			game.level.map:particleEmitter(target.x, target.y, 1, "temporal_teleport")
-			if self:checkHit(getParadoxSpellpower(self, t), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0)) and target:canBe("teleport") then
-				if not target:teleportRandom(target.x, target.y, self:getTalentRadius(t) * 4, self:getTalentRadius(t) * 2) then
-					game.logSeen(target, "The spell fizzles on %s!", target.name:capitalize())
-				else
-					target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=getParadoxSpellpower(self, t, 0.3)})
-					game.level.map:particleEmitter(target.x, target.y, 1, "temporal_teleport")
-					hit = true
-				end
-			else
-				game.logSeen(target, "%s resists the banishment!", target.name:capitalize())
-			end
-		end)
-
-		if not hit then
-			game:onTickEnd(function()
-				if not self:attr("no_talents_cooldown") then
-					self.talents_cd[self.T_BANISH] = self.talents_cd[self.T_BANISH] /2
-				end
-			end)
-		end
-
+		self:setEffect(self.EFF_PHASE_SHIFT, t.getDuration(self, t), {})
 		game:playSoundNear(self, "talents/teleport")
-
 		return true
 	end,
 	info = function(self, t)
-		local radius = self:getTalentRadius(t)
-		local range = t.getTeleport(self, t)
-		return ([[Randomly teleports all targets within a radius of %d around you.  Targets will be teleported between %d and %d tiles from their current location.
-		If no targets are teleported the cooldown will be halved.
-		The chance of teleportion will scale with your Spellpower.]]):format(radius, range / 2, range)
+		local duration = t.getDuration(self, t)
+		return ([[Phase shift yourself for %d turns; any damage greater than 10%% of your maximum life will teleport you to an adjacent tile and be reduced by 50%% (can only happen once per turn).]]):
+		format(duration)
 	end,
 }
 
@@ -949,7 +864,7 @@ newTalent{
 	requires_target = true,
 	direct_hit = true,
 	range = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9, 0.5, 0, 1)) end,
-	getConfuseDuration = function(self, t) return math.floor(self:combatTalentScale(self:getTalentLevel(t), 3, 7)) end,
+	getConfuseDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3, 7)) end,
 	getConfuseEfficency = function(self, t) return math.min(50, self:getTalentLevelRaw(t) * 10) end,
 	action = function(self, t)
 		local tg = {type="hit", range=self:getTalentRange(t)}
@@ -1076,3 +991,148 @@ newTalent{
 		format(stun, damDesc(self, DamageType.TEMPORAL, damage/2), damDesc(self, DamageType.PHYSICAL, damage/2))
 	end,
 }
+
+newTalent{
+	name = "Carbon Spikes",
+	type = {"chronomancy/other", 1},
+	no_sustain_autoreset = true,
+	points = 5,
+	mode = "sustained",
+	sustain_paradox = 20,
+	cooldown = 12,
+	tactical = { BUFF =2, DEFEND = 2 },
+	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 1, 150, getParadoxSpellpower(self, t)) end,
+	getArmor = function(self, t) return math.ceil(self:combatTalentSpellDamage(t, 20, 50, getParadoxSpellpower(self, t))) end,
+	callbackOnActBase = function(self, t)
+		local maxspikes = t.getArmor(self, t)
+		if self.carbon_armor < maxspikes then
+			self.carbon_armor = self.carbon_armor + 1
+		end
+	end,
+	do_carbonLoss = function(self, t)
+		if self.carbon_armor >= 1 then
+			self.carbon_armor = self.carbon_armor - 1
+		else
+			-- Deactivate without loosing energy
+			self:forceUseTalent(self.T_CARBON_SPIKES, {ignore_energy=true})
+		end
+	end,
+	activate = function(self, t)
+		local power = t.getArmor(self, t)
+		self.carbon_armor = power
+		game:playSoundNear(self, "talents/spell_generic")
+		return {
+			armor = self:addTemporaryValue("carbon_spikes", power),
+			onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.BLEED]=t.getDamageOnMeleeHit(self, t)}),			
+		}
+	end,
+	deactivate = function(self, t, p)
+		self:removeTemporaryValue("carbon_spikes", p.armor)
+		self:removeTemporaryValue("on_melee_hit", p.onhit)
+		self.carbon_armor = nil
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamageOnMeleeHit(self, t)
+		local armor = t.getArmor(self, t)
+		return ([[Fragile spikes of carbon protrude from your flesh, clothing, and armor, increasing your armor rating by %d and inflicting %0.2f bleed damage over six turns on attackers.   Each time you're struck, the armor increase will be reduced by 1.  Each turn the spell will regenerate 1 armor up to its starting value.
+		If the armor increase from the spell ever falls below 1, the sustain will deactivate and the effect will end.
+		The armor and bleed damage will increase with your Spellpower.]]):
+		format(armor, damDesc(self, DamageType.PHYSICAL, damage))
+	end,
+}
+
+newTalent{
+	name = "Destabilize",
+	type = {"chronomancy/other", 1},
+	points = 5,
+	cooldown = 10,
+	paradox = function (self, t) return getParadoxCost(self, t, 30) end,
+	range = 10,
+	tactical = { ATTACK = 2 },
+	requires_target = true,
+	direct_hit = true,
+	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 60, getParadoxSpellpower(self, t)) end,
+	getExplosion = function(self, t) return self:combatTalentSpellDamage(t, 20, 230, getParadoxSpellpower(self, t)) end,
+	action = function(self, t)
+		local tg = {type="hit", range=self:getTalentRange(t), talent=t}
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		self:project(tg, x, y, function(px, py)
+			local target = game.level.map(px, py, Map.ACTOR)
+			if not target then return end
+			target:setEffect(target.EFF_TEMPORAL_DESTABILIZATION, 10, {src=self, dam=t.getDamage(self, t), explosion=self:spellCrit(t.getExplosion(self, t))})
+			game.level.map:particleEmitter(target.x, target.y, 1, "entropythrust")
+		end)
+		game:playSoundNear(self, "talents/cloud")
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		local explosion = t.getExplosion(self, t)
+		return ([[Destabilizes the target, inflicting %0.2f temporal damage per turn for 10 turns.  If the target dies while destabilized, it will explode, doing %0.2f temporal damage and %0.2f physical damage in a radius of 4.
+		If the target dies while also under the effects of continuum destabilization, all explosion damage will be done as temporal damage.
+		The damage will scale with your Spellpower.]]):
+		format(damDesc(self, DamageType.TEMPORAL, damage), damDesc(self, DamageType.TEMPORAL, explosion/2), damDesc(self, DamageType.PHYSICAL, explosion/2))
+	end,
+}
+
+newTalent{
+	name = "Quantum Spike",
+	type = {"chronomancy/other", 1},
+	points = 5,
+	paradox = function (self, t) return getParadoxCost(self, t, 40) end,
+	cooldown = 4,
+	tactical = { ATTACK = {TEMPORAL = 1, PHYSICAL = 1} },
+	range = 10,
+	direct_hit = true,
+	reflectable = true,
+	requires_target = true,
+	target = function(self, t)
+		return {type="hit", range=self:getTalentRange(t), talent=t}
+	end,
+	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 30, 300, getParadoxSpellpower(self, t)) end,
+	action = function(self, t)
+		local tg = self:getTalentTarget(t)
+		local x, y, target = self:getTarget(tg)
+		if not x or not y then return nil end
+		
+		-- bonus damage on targets with temporal destabilization
+		local damage = t.getDamage(self, t)
+		if target then 
+			if target:hasEffect(target.EFF_TEMPORAL_DESTABILIZATION) or target:hasEffect(target.EFF_CONTINUUM_DESTABILIZATION) then
+				damage = damage * 1.5
+			end
+		end
+		
+		
+		self:project(tg, x, y, DamageType.MATTER, self:spellCrit(damage))
+		game:playSoundNear(self, "talents/arcane")
+		
+		-- Try to insta-kill
+		if target then
+			if target:checkHit(self:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("instakill") and target.life > 0 and target.life < target.max_life * 0.2 then
+				-- KILL IT !
+				game.logSeen(target, "%s has been pulled apart at a molecular level!", target.name:capitalize())
+				target:die(self)
+			elseif target.life > 0 and target.life < target.max_life * 0.2 then
+				game.logSeen(target, "%s resists the quantum spike!", target.name:capitalize())
+			end
+		end
+		
+		-- if we kill it use teleport particles for larger effect radius
+		if target and target.dead then
+			game.level.map:particleEmitter(x, y, 1, "teleport")
+		else
+			game.level.map:particleEmitter(x, y, 1, "entropythrust")
+		end
+		
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		return ([[Attempts to pull the target apart at a molecular level, inflicting %0.2f temporal damage and %0.2f physical damage.  If the target ends up with low enough life (<20%%), it might be instantly killed.
+		Quantum Spike deals 50%% additional damage to targets affected by temporal destabilization and/or continuum destabilization.
+		The damage will scale with your Spellpower.]]):format(damDesc(self, DamageType.TEMPORAL, damage/2), damDesc(self, DamageType.PHYSICAL, damage/2))
+	end,
+}
diff --git a/game/modules/tome/data/talents/chronomancy/spacetime-folding.lua b/game/modules/tome/data/talents/chronomancy/spacetime-folding.lua
index 5051eca5dd2c670338c3e65ec5a0502a99c74bb5..fe7e0ad055ade4b9ca6b53b35e0b9a08a35d96a4 100644
--- a/game/modules/tome/data/talents/chronomancy/spacetime-folding.lua
+++ b/game/modules/tome/data/talents/chronomancy/spacetime-folding.lua
@@ -36,7 +36,7 @@ makeWarpMine = function(self, t, x, y, type)
 		type = "temporal", id_by_type=true, unided_name = "trap",
 		display = '^', color=colors.BLUE, image = ("trap/chronomine_%s_0%d.png"):format(type == "toward" and "blue" or "red", rng.avg(1, 4, 3)),
 		shader = "shadow_simulacrum", shader_args = { color = {0.2, 0.2, 0.2}, base = 0.8, time_factor = 1500 },
-		dam = dam, t=t.id, power = power, dest_power = dest_power,
+		dam = dam, talent=t, power = power, dest_power = dest_power,
 		temporary = duration,
 		x = x, y = y, type = type,
 		summoner = self, summoner_gain_exp = true,
@@ -47,7 +47,7 @@ makeWarpMine = function(self, t, x, y, type)
 		end,
 		triggered = function(self, x, y, who)
 			-- Project our damage
-			self.summoner:project({type="hit",x=x,y=y, talent=self.t}, x, y, engine.DamageType.WARP, self.dam)
+			self.summoner:project({type="hit",x=x,y=y, talent=self.talent}, x, y, engine.DamageType.WARP, self.dam)
 			
 			-- Teleport?
 			if not who.dead then
@@ -135,11 +135,12 @@ newTalent{
 		local detect = t.trapPower(self,t)*0.8
 		local disarm = t.trapPower(self,t)
 		local duration = t.getDuration(self, t)
-		return ([[Learn to lay Warp Mines in a radius of 1 out to a range of %d.
-		Warp Mines teleport targets that trigger them either toward you or away from you depending on the type of mine used and inflict %0.2f physical and %0.2f temporal (warp) damage.
-		The mines are hidden traps (%d detection and %d disarm power based on your Magic) and last for %d turns.
-		The damage caused by your Warp Mines will improve with your Spellpower.]]):
-		format(range, damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage), detect, disarm, duration) --I5
+		return ([[Learn to lay Warp Mines in a radius of 1.  Warp Mines teleport targets that trigger them either toward you or away from you depending on the type of mine used and inflict %0.2f physical and %0.2f temporal (warp) damage.
+		The mines are hidden traps (%d detection and %d disarm power based on your Magic), last for %d turns, and share a ten turn cooldown.
+		The damage caused by your Warp Mines will improve with your Spellpower.
+		Investing in this talent improves the range of all Spacetime Folding talents.
+		Current Range: %d]]):
+		format(damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage), detect, disarm, duration, range) --I5
 	end,
 }
 
@@ -151,7 +152,7 @@ newTalent{
 	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
 	tactical = { ATTACKAREA = { TEMPORAL = 1, PHYSICAL = 1 }, CLOSEIN = 2  },
 	requires_target = true,
-	range = function(self, t) return self:callTalent(self.T_WARP_MINES, "getRange")end,
+	range = function(self, t) return self:callTalent(self.T_WARP_MINES, "getRange") or 5 end,
 	no_unlearn_last = true,
 	target = function(self, t) return {type="ball", nowarning=true, range=self:getTalentRange(t), radius=1, nolock=true, talent=t} end,	
 	action = function(self, t)
@@ -176,7 +177,7 @@ newTalent{
 			game.zone:addEntity(game.level, trap, "trap", px, py)
 		end)
 
-		game:playSoundNear(self, "talents/heal")
+		game:playSoundNear(self, "talents/warp")
 		self:startTalentCooldown(self.T_WARP_MINE_AWAY)
 		
 		return true
@@ -202,7 +203,7 @@ newTalent{
 	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
 	tactical = { ATTACKAREA = { TEMPORAL = 1, PHYSICAL = 1 }, ESCAPE = 2  },
 	requires_target = true,
-	range = function(self, t) return self:callTalent(self.T_WARP_MINES, "getRange") end,
+	range = function(self, t) return self:callTalent(self.T_WARP_MINES, "getRange") or 5 end,
 	no_unlearn_last = true,
 	target = function(self, t) return {type="ball", nowarning=true, range=self:getTalentRange(t), radius=1, nolock=true, talent=t} end,	
 	action = function(self, t)
@@ -227,7 +228,7 @@ newTalent{
 			game.zone:addEntity(game.level, trap, "trap", px, py)
 		end)
 
-		game:playSoundNear(self, "talents/heal")
+		game:playSoundNear(self, "talents/warp")
 		self:startTalentCooldown(self.T_WARP_MINE_TOWARD)
 		
 		return true
@@ -240,145 +241,26 @@ newTalent{
 		return ([[Lay Warp Mines in a radius of 1 that teleport enemies away from you and inflict %0.2f physical and %0.2f temporal (warp) damage.
 		The mines are hidden traps (%d detection and %d disarm power based on your Magic) and last for %d turns.
 		The damage caused by your Warp Mines will improve with your Spellpower.
-		Using this talent will trigger the cooldown on Warp Mine Away.]]):
+		Using this talent will trigger the cooldown on Warp Mine Toward.]]):
 		format(damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage), detect, disarm, duration) 
 	end,
 }
 
 newTalent{
-	name = "Wormhole",
+	name = "Spatial Tether",
 	type = {"chronomancy/spacetime-folding", 2},
 	require = chrono_req2,
 	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
-	cooldown = 10,
-	tactical = { ESCAPE = 2 },
-	range = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9, 0.5, 0, 1)) end,
-	radius = function(self, t) return math.floor(self:combatTalentLimit(t, 1, 7, 3)) end, -- Limit to radius 1
-	requires_target = true,
-	getDuration = function (self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(self:getTalentLevel(t), 6, 10))) end,
-	no_npc_use = true,
-	action = function(self, t)
-		-- Target the entrance location
-		local tg = {type="bolt", nowarning=true, range=1, nolock=true, simple_dir_request=true, talent=t}
-		local entrance_x, entrance_y = self:getTarget(tg)
-		if not entrance_x or not entrance_y then return nil end
-		local _ _, entrance_x, entrance_y = self:canProject(tg, entrance_x, entrance_y)
-		local trap = game.level.map(entrance_x, entrance_y, engine.Map.TRAP)
-		if trap or game.level.map:checkEntity(entrance_x, entrance_y, Map.TERRAIN, "block_move") then game.logPlayer(self, "You can't place a wormhole entrance here.") return end
-
-		-- Target the exit location
-		local tg = {type="hit", nolock=true, pass_terrain=true, nowarning=true, range=self:getTalentRange(t)}
-		local exit_x, exit_y = self:getTarget(tg)
-		if not exit_x or not exit_y then return nil end
-		local _ _, exit_x, exit_y = self:canProject(tg, exit_x, exit_y)
-		local trap = game.level.map(exit_x, exit_y, engine.Map.TRAP)
-		if trap or game.level.map:checkEntity(exit_x, exit_y, Map.TERRAIN, "block_move") or core.fov.distance(entrance_x, entrance_y, exit_x, exit_y) < 2 then game.logPlayer(self, "You can't place a wormhole exit here.") return end
-
-		-- Wormhole values
-		local power = getParadoxSpellpower(self, t)
-		local dest_power = getParadoxSpellpower(self, t, 0.3)
-		
-		-- Our base wormhole
-		local function makeWormhole(x, y, dest_x, dest_y)
-			local wormhole = mod.class.Trap.new{
-				name = "wormhole",
-				type = "annoy", subtype="teleport", id_by_type=true, unided_name = "trap",
-				image = "terrain/wormhole.png",
-				display = '&', color_r=255, color_g=255, color_b=255, back_color=colors.STEEL_BLUE,
-				message = "@Target@ moves onto the wormhole.",
-				temporary = t.getDuration(self, t),
-				x = x, y = y, dest_x = dest_x, dest_y = dest_y,
-				radius = self:getTalentRadius(t),
-				canAct = false,
-				energy = {value=0},
-				disarm = function(self, x, y, who) return false end,
-				power = power, dest_power = dest_power,
-				summoned_by = self, -- "summoner" is immune to it's own traps
-				triggered = function(self, x, y, who)
-					local hit = who == self.summoned_by or who:checkHit(self.power, who:combatSpellResist()+(who:attr("continuum_destabilization") or 0), 0, 95) and who:canBe("teleport") -- Bug fix, Deprecrated checkhit call
-					if hit then
-						game.level.map:particleEmitter(who.x, who.y, 1, "temporal_teleport")
-						if not who:teleportRandom(self.dest_x, self.dest_y, self.radius, 1) then
-							game.logSeen(who, "%s tries to enter the wormhole but a violent force pushes it back.", who.name:capitalize())
-						else
-							if who ~= self.summoned_by then who:setEffect(who.EFF_CONTINUUM_DESTABILIZATION, 100, {power=self.dest_power}) end
-							game.level.map:particleEmitter(who.x, who.y, 1, "temporal_teleport")
-							game:playSoundNear(self, "talents/teleport")
-						end
-					else
-						game.logSeen(who, "%s ignores the wormhole.", who.name:capitalize())
-					end
-					return true
-				end,
-				act = function(self)
-					self:useEnergy()
-					self.temporary = self.temporary - 1
-					if self.temporary <= 0 then
-						game.logSeen(self, "Reality asserts itself and forces the wormhole shut.")
-						if game.level.map(self.x, self.y, engine.Map.TRAP) == self then game.level.map:remove(self.x, self.y, engine.Map.TRAP) end
-						game.level:removeEntity(self)
-					end
-				end,
-			}
-			
-			return wormhole
-		end
-		
-		-- Adding the entrance wormhole
-		local entrance = makeWormhole(entrance_x, entrance_y, exit_x, exit_y)
-		game.level:addEntity(entrance)
-		entrance:identify(true)
-		entrance:setKnown(self, true)
-		game.zone:addEntity(game.level, entrance, "trap", entrance_x, entrance_y)
-		entrance.faction = nil
-		game:playSoundNear(self, "talents/heal")
-
-		-- Adding the exit wormhole
-		local exit = makeWormhole(exit_x, exit_y, entrance_x, entrance_y)
-		exit.x = exit_x
-		exit.y = exit_y
-		game.level:addEntity(exit)
-		exit:identify(true)
-		exit:setKnown(self, true)
-		game.zone:addEntity(game.level, exit, "trap", exit_x, exit_y)
-		exit.faction = nil
-
-		-- Linking the wormholes
-		entrance.dest = exit
-		exit.dest = entrance
-
-		game.logSeen(self, "%s folds the space between two points.", self.name)
-		return true
-	end,
-	info = function(self, t)
-		local duration = t.getDuration(self, t)
-		local radius = self:getTalentRadius(t)
-		local range = self:getTalentRange(t)
-		return ([[You fold the space between yourself and a second point within a range of %d, creating a pair of wormholes.  Any creature stepping on either wormhole will be teleported near the other (radius %d accuracy).  
-		The wormholes will last %d turns and must be placed at least two tiles apart.
-		The chance of teleporting enemies will scale with your Spellpower.]])
-		:format(range, radius, duration)
-	end,
-}
-
-newTalent{
-	name = "Spatial Tether",
-	type = {"chronomancy/spacetime-folding", 3},
-	require = chrono_req3,
-	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
-	cooldown = 10,
+	paradox = function (self, t) return getParadoxCost(self, t, 12) end,
+	cooldown = 8,
 	tactical = { DISABLE = 2 },
-	range = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9, 0.5, 0, 1)) end,
+	range = function(self, t) return self:callTalent(self.T_WARP_MINES, "getRange") or 5 end,
 	requires_target = true,
-	getDuration = function (self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(self:getTalentLevel(t), 6, 10))) end,
-	getChance = function(self, t) return paradoxTalentScale(self, t, 10, 20, 30) end,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 200, getParadoxSpellpower(self, t)) end,
+	getDuration = function (self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 6, 10))) end,
+	getChance = function(self, t) return self:combatTalentLimit(t, 30, 10, 20) end,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), nowarning=true, talent=t}
 	end,
-	no_energy=true,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
@@ -446,31 +328,31 @@ newTalent{
 		game.level.map(x, y, Map.TERRAIN, tether)
 		game.nicer_tiles:updateAround(game.level, x, y)
 		game.level.map:updateMap(x, y)
-		game:playSoundNear(self, "talents/heal")
+		game:playSoundNear(self, "talents/warp")
 		
 		return true
 	end,
 	info = function(self, t)
 		local duration = t.getDuration(self, t)
 		local chance = t.getChance(self, t)
-		return ([[Tethers the target to the location for %d turns.  For each tile the target moves away from the target location it has a %d%% chance each turn of being teleported back to the tether.
-		The teleportation chance scales with your Spellpower.]])
+		return ([[Tethers the target to the location for %d turns.  For each tile the target moves away from the target location it has a %d%% chance each turn of being teleported back to the tether.]])
 		:format(duration, chance)
 	end,
 }
 
 newTalent{
 	name = "Dimensional Anchor",
-	type = {"chronomancy/spacetime-folding", 4},
-	require = chrono_req4,
+	type = {"chronomancy/spacetime-folding", 3},
+	require = chrono_req3,
 	points = 5,
 	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
 	cooldown = 12,
 	tactical = { DISABLE = 2 },
-	range = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9, 0.5, 0, 1)) end,
+	range = function(self, t) return self:callTalent(self.T_WARP_MINES, "getRange") or 5 end,
 	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 230, getParadoxSpellpower(self, t)) end,
 	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 6, 10))) end,
+	getDaze = function(self, t) return math.floor(self:combatTalentScale(t, 1, 2)) end,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), friendlyfire=false, radius=self:getTalentRadius(t), talent=t}
 	end,
@@ -483,8 +365,8 @@ newTalent{
 		local _ _, _, _, x, y = self:canProject(tg, x, y)
 
 		local particle
-		if core.shader.active(4) then
-			particle = {type="volumetric", args={radius=self:getTalentRadius(t)+2, kind="fast_sphere", img="moony_01", density=60, shininess=50, scrollingSpeed=-0.004}, only_one=true}
+		if core.shader.allow("volumetric") then
+			particle = {type="volumetric", args={radius=self:getTalentRadius(t)*2, kind="fast_sphere", img="moony_01", density=60, shininess=50, scrollingSpeed=-0.004}, only_one=true}
 		else
 			particle = {type="temporal_cloud"}
 		end
@@ -493,14 +375,14 @@ newTalent{
 		local dam = self:spellCrit(t.getDamage(self, t))
 		game.level.map:addEffect(self,
 			x, y, t.getDuration(self,t),
-			DamageType.DIMENSIONAL_ANCHOR, {dam=dam, dur=1, src=self, apply=getParadoxSpellpower(self, t)},
+			DamageType.DIMENSIONAL_ANCHOR, {dam=dam, dur=1, daze=t.getDaze(self, t), src=self, apply=getParadoxSpellpower(self, t)},
 			self:getTalentRadius(t),
 			5, nil,
 			particle,
 			nil, false, false
 		)
 
-		game:playSoundNear(self, "talents/teleport")
+		game:playSoundNear(self, "talents/warp")
 
 		return true
 	end,
@@ -508,7 +390,70 @@ newTalent{
 		local damage = t.getDamage(self, t)/2
 		local radius = self:getTalentRadius(t)
 		local duration = t.getDuration(self, t)
-		return ([[Create a radius %d anti-telport field for %d turns.  Enemies in the field will be anchored, preventing teleportation and taking %0.2f physical and %0.2f temporal (warp) damage on teleport attempts.
-		The damage will scale with your Spellpower.]]):format(radius, duration, damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage))
+		local daze = t.getDaze(self, t)
+		return ([[Create a radius %d anti-teleport field for %d turns.  
+		Enemies in the field will be anchored, preventing teleportation and taking %0.2f physical and %0.2f temporal (warp) damage, as well as becoming dazed for %d turns, on teleport attempts.
+		The damage will scale with your Spellpower.]]):format(radius, duration, damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage), daze)
+	end,
+}
+
+newTalent{
+	name = "Banish",
+	type = {"chronomancy/spacetime-folding", 4},
+	require = chrono_req4,
+	points = 5,
+	paradox = function (self, t) return getParadoxCost(self, t, 12) end,
+	cooldown = 10,
+	tactical = { ESCAPE = 2 },
+	range = function(self, t) return self:callTalent(self.T_WARP_MINES, "getRange") or 5 end,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 5.5)) end,
+	getTeleport = function(self, t) return math.floor(self:combatTalentScale(t, 8, 16)) end,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
+	end,
+	requires_target = true,
+	direct_hit = true,
+	action = function(self, t)
+		local tg = self:getTalentTarget(t)
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		local hit = false
+
+		self:project(tg, x, y, function(px, py)
+			local target = game.level.map(px, py, Map.ACTOR)
+			if not target or target == self then return end
+			game.level.map:particleEmitter(target.x, target.y, 1, "temporal_teleport")
+			if self:checkHit(getParadoxSpellpower(self, t), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0)) and target:canBe("teleport") then
+				if not target:teleportRandom(target.x, target.y, self:getTalentRadius(t) * 4, self:getTalentRadius(t) * 2) then
+					game.logSeen(target, "The spell fizzles on %s!", target.name:capitalize())
+				else
+					target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=getParadoxSpellpower(self, t, 0.3)})
+					game.level.map:particleEmitter(target.x, target.y, 1, "temporal_teleport")
+					hit = true
+				end
+			else
+				game.logSeen(target, "%s resists the banishment!", target.name:capitalize())
+			end
+		end)
+		
+		if not hit then
+			game:onTickEnd(function()
+				if not self:attr("no_talents_cooldown") then
+					self.talents_cd[self.T_BANISH] = self.talents_cd[self.T_BANISH] /2
+				end
+			end)
+		end
+
+		game:playSoundNear(self, "talents/teleport")
+
+		return true
+	end,
+	info = function(self, t)
+		local radius = self:getTalentRadius(t)
+		local range = t.getTeleport(self, t)
+		return ([[Randomly teleports all targets within a radius of %d.  Targets will be teleported between %d and %d tiles from their current location.
+		If no targets are teleported the cooldown will be halved.
+		The chance of teleportion will scale with your Spellpower.]]):format(radius, range / 2, range)
 	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua b/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
index a4969e6ce84e1a5e3393d657caa403d20bd58b65..0f037706dc42a40588edf900317a2112f2c3ffb9 100644
--- a/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
+++ b/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
@@ -121,6 +121,14 @@ newTalent{
 				self:removeEffect(eff.effect_id)
 			end
 		end
+		
+		-- Make sure we update the display for blind and such
+		game:onTickEnd(function()
+			if game.level then
+				self:resetCanSeeCache()
+				if self.player then for uid, e in pairs(game.level.entities) do if e.x then game.level.map:updateMap(e.x, e.y) end end game.level.map.changed = true end
+			end
+		end)
 
 	end,
 	info = function(self, t)
@@ -132,23 +140,119 @@ newTalent{
 }
 
 newTalent{
-	name = "Phase Shift",
+	name = "Wormhole",
 	type = {"chronomancy/spacetime-weaving", 3},
 	require = chrono_req3,
 	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
-	cooldown = 24,
-	tactical = { DEFEND = 2 },
-	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentLimit(t, 25, 3, 7, true))) end,
+	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
+	cooldown = 10,
+	tactical = { ESCAPE = 2 },
+	range = 10,
+	radius = function(self, t) return math.floor(self:combatTalentLimit(t, 1, 5, 2)) end, -- Limit to radius 1
+	requires_target = true,
+	getDuration = function (self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 6, 10))) end,
+	no_npc_use = true,
 	action = function(self, t)
-		self:setEffect(self.EFF_PHASE_SHIFT, t.getDuration(self, t), {})
-		game:playSoundNear(self, "talents/teleport")
+		-- Target the entrance location
+		local tg = {type="bolt", nowarning=true, range=1, nolock=true, simple_dir_request=true, talent=t}
+		local entrance_x, entrance_y = self:getTarget(tg)
+		if not entrance_x or not entrance_y then return nil end
+		local _ _, entrance_x, entrance_y = self:canProject(tg, entrance_x, entrance_y)
+		local trap = game.level.map(entrance_x, entrance_y, engine.Map.TRAP)
+		if trap or game.level.map:checkEntity(entrance_x, entrance_y, Map.TERRAIN, "block_move") then game.logPlayer(self, "You can't place a wormhole entrance here.") return end
+
+		-- Target the exit location
+		local tg = {type="hit", nolock=true, pass_terrain=true, nowarning=true, range=self:getTalentRange(t)}
+		local exit_x, exit_y = self:getTarget(tg)
+		if not exit_x or not exit_y then return nil end
+		local _ _, exit_x, exit_y = self:canProject(tg, exit_x, exit_y)
+		local trap = game.level.map(exit_x, exit_y, engine.Map.TRAP)
+		if trap or game.level.map:checkEntity(exit_x, exit_y, Map.TERRAIN, "block_move") or core.fov.distance(entrance_x, entrance_y, exit_x, exit_y) < 2 then game.logPlayer(self, "You can't place a wormhole exit here.") return end
+
+		-- Wormhole values
+		local power = getParadoxSpellpower(self, t)
+		local dest_power = getParadoxSpellpower(self, t, 0.3)
+		
+		-- Our base wormhole
+		local function makeWormhole(x, y, dest_x, dest_y)
+			local wormhole = mod.class.Trap.new{
+				name = "wormhole",
+				type = "annoy", subtype="teleport", id_by_type=true, unided_name = "trap",
+				image = "terrain/wormhole.png",
+				display = '&', color_r=255, color_g=255, color_b=255, back_color=colors.STEEL_BLUE,
+				message = "@Target@ moves onto the wormhole.",
+				temporary = t.getDuration(self, t),
+				x = x, y = y, dest_x = dest_x, dest_y = dest_y,
+				radius = self:getTalentRadius(t),
+				canAct = false,
+				energy = {value=0},
+				disarm = function(self, x, y, who) return false end,
+				power = power, dest_power = dest_power,
+				summoned_by = self, -- "summoner" is immune to it's own traps
+				triggered = function(self, x, y, who)
+					local hit = who == self.summoned_by or who:checkHit(self.power, who:combatSpellResist()+(who:attr("continuum_destabilization") or 0), 0, 95) and who:canBe("teleport") -- Bug fix, Deprecrated checkhit call
+					if hit then
+						game.level.map:particleEmitter(who.x, who.y, 1, "temporal_teleport")
+						if not who:teleportRandom(self.dest_x, self.dest_y, self.radius, 1) then
+							game.logSeen(who, "%s tries to enter the wormhole but a violent force pushes it back.", who.name:capitalize())
+						else
+							if who ~= self.summoned_by then who:setEffect(who.EFF_CONTINUUM_DESTABILIZATION, 100, {power=self.dest_power}) end
+							game.level.map:particleEmitter(who.x, who.y, 1, "temporal_teleport")
+							game:playSoundNear(self, "talents/teleport")
+						end
+					else
+						game.logSeen(who, "%s ignores the wormhole.", who.name:capitalize())
+					end
+					return true
+				end,
+				act = function(self)
+					self:useEnergy()
+					self.temporary = self.temporary - 1
+					if self.temporary <= 0 then
+						game.logSeen(self, "Reality asserts itself and forces the wormhole shut.")
+						if game.level.map(self.x, self.y, engine.Map.TRAP) == self then game.level.map:remove(self.x, self.y, engine.Map.TRAP) end
+						game.level:removeEntity(self)
+					end
+				end,
+			}
+			
+			return wormhole
+		end
+		
+		-- Adding the entrance wormhole
+		local entrance = makeWormhole(entrance_x, entrance_y, exit_x, exit_y)
+		game.level:addEntity(entrance)
+		entrance:identify(true)
+		entrance:setKnown(self, true)
+		game.zone:addEntity(game.level, entrance, "trap", entrance_x, entrance_y)
+		entrance.faction = nil
+		game:playSoundNear(self, "talents/heal")
+
+		-- Adding the exit wormhole
+		local exit = makeWormhole(exit_x, exit_y, entrance_x, entrance_y)
+		exit.x = exit_x
+		exit.y = exit_y
+		game.level:addEntity(exit)
+		exit:identify(true)
+		exit:setKnown(self, true)
+		game.zone:addEntity(game.level, exit, "trap", exit_x, exit_y)
+		exit.faction = nil
+
+		-- Linking the wormholes
+		entrance.dest = exit
+		exit.dest = entrance
+
+		game.logSeen(self, "%s folds the space between two points.", self.name)
 		return true
 	end,
 	info = function(self, t)
 		local duration = t.getDuration(self, t)
-		return ([[Phase shift yourself for %d turns; any damage greater than 10%% of your maximum life will teleport you to an adjacent tile and be reduced by 50%% (can only happen once per turn).]]):
-		format(duration)
+		local radius = self:getTalentRadius(t)
+		local range = self:getTalentRange(t)
+		return ([[You fold the space between yourself and a second point within a range of %d, creating a pair of wormholes.  Any creature stepping on either wormhole will be teleported near the other (radius %d accuracy).  
+		The wormholes will last %d turns and must be placed at least two tiles apart.
+		The chance of teleporting enemies will scale with your Spellpower.]])
+		:format(range, radius, duration)
 	end,
 }
 
@@ -156,37 +260,36 @@ newTalent{
 	name = "Phase Pulse",
 	type = {"chronomancy/spacetime-weaving", 4},
 	require = chrono_req4,
-	tactical = { ATTACKAREA = {TEMPORAL = 1, PHYSICAL = 1} },
+	tactical = { DISABLE = 2 },
 	mode = "sustained",
 	sustain_paradox = 36,
 	cooldown = 10,
 	points = 5,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 15, 70, getParadoxSpellpower(self, t)) end,
 	range = 0,
-	radius = function(self, t) return math.floor(self:combatTalentScale(t, 1.5, 3.5)) end,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 1, 2)) end,
 	target = function(self, t)
 		return {type="ball", range=100, radius=self:getTalentRadius(t), selffire=false, talent=t}
 	end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 2, 3))) end,
+	getChance = function(self, t) return 2 + math.floor(self:combatTalentScale(t, 2, 10)) end,
 	doPulse = function(self, t, ox, oy, fail)
 		local tg = self:getTalentTarget(t)
-		local dam = self:spellCrit(t.getDamage(self, t))
 		local distance = core.fov.distance(self.x, self.y, ox, oy)
-		local chance = distance * 10
+		local chance = distance * t.getChance(self, t)
 		
-		if not fail then
-			dam = dam * (1 + math.min(1, distance/10))
-			game:onTickEnd(function()
-				self:project(tg, ox, oy, DamageType.WARP, dam)
-				self:project(tg, self.x, self.y, DamageType.WARP, dam)
+		-- Project our status effects at the end of the turn
+		game:onTickEnd(function()
+			-- Project at both the entrance and exit
+			self:project(tg, self.x, self.y, function(px, py)
+				local target = game.level.map(px, py, Map.ACTOR)
+				if target and rng.percent(chance) then randomWarpEffect(self, t, target) end
 			end)
-		else
-			dam = dam *2
-			chance = 100
-			tg.radius = tg.radius * 2
-			game:onTickEnd(function()
-				self:project(tg, self.x, self.y, DamageType.WARP, dam)
+			self:project(tg, ox, oy, function(px, py)
+				local target = game.level.map(px, py, Map.ACTOR)
+				if target and rng.percent(chance) then randomWarpEffect(self, t, target) end
 			end)
-		end
+		end)
+			
 	end,
 	activate = function(self, t)
 		game:playSoundNear(self, "talents/spell_generic")
@@ -196,11 +299,11 @@ newTalent{
 		return true
 	end,
 	info = function(self, t)
-		local damage = t.getDamage(self, t)/2
+		local chance = t.getChance(self, t)
 		local radius = self:getTalentRadius(t)
-		return ([[When you teleport with Phase Pulse active you deal %0.2f physical and %0.2f temporal (warp) damage to all targets in a radius of %d around you.
-		For each space you move from your original location the damage is increased by 10%% (to a maximum bonus of 100%%).  If the teleport fails, the blast radius and damage will be doubled.
-		This effect occurs both at the entrance and exist locations and the damage will scale with your Spellpower.]]):
-		format(damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage), radius)
+		local duration = t.getDuration(self, t)
+		return ([[When you teleport you fire a pulse that jolts enemies out of phase in a radius of %d around both the start and the destination point. 
+		Each target has a %d%% chance per tile you travelled to be stunned, blinded, confused, or pinned for %d turns.]]):
+		format(radius, chance, duration)
 	end,
-}
+}
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/chronomancy/spatial-tears.lua b/game/modules/tome/data/talents/chronomancy/spatial-tears.lua
deleted file mode 100644
index 8c7ef9e5dfbc4e5fb080f9cb691ebfb0b6c66a1e..0000000000000000000000000000000000000000
--- a/game/modules/tome/data/talents/chronomancy/spatial-tears.lua
+++ /dev/null
@@ -1,316 +0,0 @@
--- ToME - Tales of Maj'Eyal
--- Copyright (C) 2009 - 2015 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
-
--- EDGE TODO: Particles, Timed Effect Particles
-
-local Object = require "mod.class.Object"
-
-newTalent{
-	name = "Spatial Fragments",
-	type = {"chronomancy/spatial-tears",1},
-	require = chrono_req_high1,
-	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
-	cooldown = 3,
-	tactical = { ATTACK = { TEMPORAL = 1, PHYSICAL = 1 }, },
-	range = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9, 0.5, 0, 1)) end,
-	proj_speed = 4,
-	target = function(self, t)
-		return {type="bolt", range=self:getTalentRange(t), talent=t, nowarning=true, display={particle="arrow", particle_args={tile=("particles_images/spatial_fragment"):format(rng.range(1, 4))}}}
-	end,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 100, getParadoxSpellpower(self, t)) end,
-	action = function(self, t)
-		local p = self:isTalentActive(self.T_FRACTURED_SPACE)
-		
-		local tg = self:getTalentTarget(t)
-		-- Beam?
-		local beam = self:isTalentActive(self.T_FRACTURED_SPACE) and self:isTalentActive(self.T_FRACTURED_SPACE).charges >=6 or false
-		if beam then
-			tg.type = "beam"
-		end
-		local x, y, target = self:getTarget(tg)
-		if not x or not y then return nil end
-		if beam then self:isTalentActive(self.T_FRACTURED_SPACE).charges = 0 end
-		
-		-- Fire one bolt per available target
-		if target == self then
-			-- Find available targets
-			local tgts = {}
-			local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true)
-			for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do
-				local a = game.level.map(x, y, Map.ACTOR)
-				if a and self:reactionToward(a) < 0 then
-					tgts[#tgts+1] = a
-				end
-			end end
-			
-			-- Fire a bolt at each one			
-			local dam = self:spellCrit(t.getDamage(self, t))
-			for i = 1, 3 do
-				if #tgts <= 0 then break end
-				local a, id = rng.table(tgts)
-				table.remove(tgts, id)
-				self:projectile(tg, a.x, a.y, DamageType.WARP, dam, nil)
-			end
-		else
-			-- Fire all bolts at one target
-			local dam = self:spellCrit(t.getDamage(self, t))
-			for i = 1, 3 do
-				self:projectile(tg, x, y, DamageType.WARP, dam, nil)
-			end
-		end
-	
-		game:playSoundNear(self, "talents/earth")
-		return true
-	end,
-	info = function(self, t)
-		local damage = t.getDamage(self, t)/2
-		return ([[Fire three Spatial Fragments at the target that each inflict %0.2f physical and %0.2f temporal (warp) damage.  If you target yourself you'll instead fire one Spatial Fragment at up to three targets within range.
-		If Fractured Space is fully charged the projectiles will be able to pierce through targets.  This will consume your Fractured Space charges.
-		The damage scales with your Spellpower.]])
-		:format(damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage))
-	end,
-}
-
-newTalent{
-	name = "Discontinuity",
-	type = {"chronomancy/spatial-tears", 2},
-	require = chrono_req_high2,
-	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
-	cooldown = 6,
-	tactical = { ATTACK = { TEMPORAL = 1, PHYSICAL = 1 }, },
-	range = 10,
-	direct_hit = true,
-	requires_target = true,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
-	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 6, 10)) end,
-	getLength = function(self, t) return 1 + math.floor(self:combatTalentScale(t, 3, 7)/2)*2 end,
-	target = function(self, t)
-		local halflength = math.floor(t.getLength(self,t)/2)
-		local block = function(_, lx, ly)
-			return game.level.map:checkAllEntities(lx, ly, "block_move")
-		end
-		return {type="wall", range=self:getTalentRange(t), halflength=halflength, talent=t, halfmax_spots=halflength+1, block_radius=block}
-	end,
-	action = function(self, t)
-		local tg = self:getTalentTarget(t)
-		local x, y = self:getTarget(tg)
-		if not x or not y then return nil end
-		local _ _, _, _, x, y = self:canProject(tg, x, y)
-		if game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move") then return nil end
-		
-		local damage = self:spellCrit(t.getDamage(self, t))
-		local block = self:isTalentActive(self.T_FRACTURED_SPACE) and self:isTalentActive(self.T_FRACTURED_SPACE).charges >=6 or false
-		if block then self:isTalentActive(self.T_FRACTURED_SPACE).charges = 0 end
-		self:project(tg, x, y, function(px, py, tg, self)
-			local oe = game.level.map(px, py, Map.TERRAIN)
-			if not oe or oe.special then return end
-			if not oe or oe:attr("temporary") or game.level.map:checkAllEntities(px, py, "block_move") then return end
-			local e = Object.new{
-				old_feat = oe,
-				type = "void", subtype = "void",
-				name = "discontinuity",
-				display = ' ', image = ("terrain/rift/rift_floor_0%d.png"):format(rng.avg(0, 4, 3)),
-				_noalpha = false,
-				always_remember = true,
-				does_block_move = block,
-				block_move = block,
-				pass_projectile = true,
-				is_void = true,
-				can_pass = {pass_void=1},
-				show_tooltip = true,
-				temporary = t.getDuration(self, t),
-				x = px, y = py,
-				dam = damage,
-				canAct = false,
-				t = t.id,
-				act = function(self)
-					local tg = {type="ball", range=0, friendlyfire=false, radius = 1, talent=self.t, x=self.x, y=self.y,}
-					self.summoner.__project_source = self
-					local grids = self.summoner:project(tg, self.x, self.y, engine.DamageType.WARP, self.dam)
-					if core.shader.active() then
-						game.level.map:particleEmitter(self.x, self.y, tg.radius, "starfall", {radius=tg.radius, tx=self.x, ty=self.y})
-					else
-						game.level.map:particleEmitter(self.x, self.y, tg.radius, "shadow_flash", {radius=tg.radius, grids=grids, tx=self.x, ty=self.y})
-					end
-					self.summoner.__project_source = nil
-					self:useEnergy()
-					self.temporary = self.temporary - 1
-					if self.temporary <= 0 then
-						game.level.map(self.x, self.y, engine.Map.TERRAIN, self.old_feat)
-						game.level:removeEntity(self)
-						game.level.map:updateMap(self.x, self.y)
-						game.nicer_tiles:updateAround(game.level, self.x, self.y)
-					end
-				end,
-				dig = function(src, x, y, old)
-					game.level:removeEntity(old)
-					return nil, old.old_feat
-				end,
-				summoner_gain_exp = true,
-				summoner = self,
-			}
-			e.tooltip = mod.class.Grid.tooltip
-			game.level:addEntity(e)
-			game.level.map(px, py, Map.TERRAIN, e)
-			if not block then
-				game.nicer_tiles:updateAround(game.level, px, py)
-				game.level.map:updateMap(px, py)
-			end
-		end)
-		
-		return true
-	end,
-	info = function(self, t)
-		local damage = t.getDamage(self, t)/2
-		local length = t.getLength(self, t)
-		local duration = t.getDuration(self, t)
-		return ([[Create a void wall of length %d that lasts %d turns.  Each turn the wall deals %0.2f physical and %0.2f temporal (warp) damage to all enemies within a radius of 1.
-		If Fractured Space is fully charged the wall will block movement, but not sight or projectiles.  This will consume your Fractured Space charges.
-		The damage will scale with your Spellpower.]])
-		:format(length, duration, damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage))
-	end,
-}
-
-newTalent{
-	name = "Fractured Space",
-	type = {"chronomancy/spatial-tears",3},
-	require = chrono_req_high3,
-	mode = "sustained",
-	sustain_paradox = 24,
-	cooldown = 10,
-	tactical = { BUFF = 2 },
-	points = 5,
-	getDamage = function(self, t) return self:combatTalentLimit(t, 100, 10, 75)/12 end,
-	getChance = function(self, t) return self:combatTalentLimit(t, 100, 10, 75)/6 end,
-	iconOverlay = function(self, t, p)
-		local val = p.charges or 0
-		if val <= 0 then return "" end
-		local fnt = "buff_font"
-		return tostring(math.ceil(val)), fnt
-	end,
-	callbackOnActBase = function(self, t)
-		-- Charge decay
-		local p = self:isTalentActive(self.T_FRACTURED_SPACE)
-		p.decay = p.decay + 1
-		if p.decay >=2 then
-			p.decay = 0
-			p.charges = math.max(p.charges - 1, 0)
-		end
-	end,
-	activate = function(self, t)
-		game:playSoundNear(self, "talents/heal")
-		--local particle = Particles.new("ultrashield", 1, { rm=0, rM=176, gm=196, gM=255, bm=222, bM=255, am=25, aM=125, radius=0.2, density=30, life=28, instop=-40})
-		return {
-			charges = 0, decay = 0
-		--	particle = self:addParticles(particle)
-		}
-	end,
-	deactivate = function(self, t, p)
-	--	self:removeParticles(p.particle)
-		return true
-	end,
-	info = function(self, t)
-		local damage = t.getDamage(self, t)
-		local chance = t.getChance(self, t)
-		local charges = self:isTalentActive(self.T_FRACTURED_SPACE) and self:isTalentActive(self.T_FRACTURED_SPACE).charges or 0
-		return ([[Each time you deal warp damage Fractured Space gains one charge, up to a maximum of six charges.  If you're not generating charges one charge will decay every other turn.
-		Each charge increases warp damage by %d%% and gives your Warp damage a %d%% chance to stun, blind, pin, or confuse affected targets for 3 turns.
-		If Fractured Space is fully charged, your Spatial Tears talents will consume them when cast and have bonus effects (see indvidual talent descriptions).
-		
-		Current damage bonus:   %d%%
-		Current effect chance:  %d%%]]):format(damage, chance, damage * charges, chance * charges)
-	end,
-}
-
-newTalent{
-	name = "Sphere of Destruction",
-	type = {"chronomancy/spatial-tears", 4},
-	require = chrono_req_high4,
-	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 18) end,
-	cooldown = 18,
-	tactical = { ATTACKAREA = {PHYSICAL = 2, TEMPORAL = 2} },
-	range = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9, 0.5, 0, 1)) end,
-	radius = 3,
-	proj_speed = 3,
-	target = function(self, t)
-		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
-	end,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 100, getParadoxSpellpower(self, t)) end,
-	action = function(self, t)
-		local particle = {particle="icestorm"}
-		if core.shader.active(4) then
-			particle = {particle="volumetric", particle_args={kind="fast_sphere", shininess=60, density=80, scrollingSpeed=0.02, radius=1.2, img="moony_bright_01"}}
-		end
-		local tg = {type="beam", range=self:getTalentRange(t), talent=t, display=particle}
-		local x, y = self:getTarget(tg)
-		if not x or not y  then return nil end
-		local _ _, _, _, x, y = self:canProject(tg, x, y)
-		
-		-- Store some values inside the target table so they're not lost when we reload
-		tg.chrono_sphere = {}
-		tg.chrono_sphere.dam = self:spellCrit(t.getDamage(self, t))
-		tg.chrono_sphere.strip = self:isTalentActive(self.T_FRACTURED_SPACE) and self:isTalentActive(self.T_FRACTURED_SPACE).charges >=6 or false
-		if tg.chrono_sphere.strip then self:isTalentActive(self.T_FRACTURED_SPACE).charges = 0; tg.chrono_sphere.power = getParadoxSpellpower(self, t) end
-		
-		-- A beam projectile
-		self:projectile(tg, x, y, function(px, py, tg, self)
-			-- That projects balls as it moves
-			local tg2 = self:getTalentTarget(self:getTalentFromId(self.T_SPHERE_OF_DESTRUCTION))
-			self:project(tg2, px, py, function(px2, py2)
-				local DamageType = require "engine.DamageType"
-				DamageType:get(DamageType.WARP).projector(self, px2, py2, DamageType.WARP, tg.chrono_sphere.dam)
-				
-				-- Do we strip a sustain?
-				if tg.chrono_sphere.strip then
-					local target = game.level.map(px2, py2, engine.Map.ACTOR)
-					if not target then return end
-
-					local effs = {}
-					-- Go through all sustained spells
-					for tid, act in pairs(target.sustain_talents) do
-						if act then
-							effs[#effs+1] = {"talent", tid}
-						end
-					end
-
-					if #effs == 0 then return end
-					local eff = rng.table(effs)
-
-					if self:checkHit(tg.chrono_sphere.power, target:combatSpellResist(), 0, 95, 5) then
-						target:crossTierEffect(target.EFF_SPELLSHOCKED, tg.chrono_sphere.power)
-						target:forceUseTalent(eff[2], {ignore_energy=true})
-					end
-				end
-			end)
-		end)
-		
-		game:playSoundNear(self, "talents/icestorm")
-		return true
-	end,
-	info = function(self, t)
-		local damage = t.getDamage(self, t)/2
-		return ([[Create a Sphere of Destruction that travels towards the target location, inflicting %0.2f physical and %0.2f temporal (warp) damage in a radius of three.
-		If Fractured Space is fully charged the Sphere will remove a single sustain from targets it damages.  This will consume your Fractured Space charges.
-		The sphere can hit a single target multiple times in one turn and the damage will scale with your Spellpower.]])
-		:format(damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.TEMPORAL, damage))
-	end,
-}
diff --git a/game/modules/tome/data/talents/chronomancy/speed-control.lua b/game/modules/tome/data/talents/chronomancy/speed-control.lua
index e2ea8c527e79fe14902a2139a592afb3ad6a81ba..4ef265bea9067bd37120b54bbb340f89f7a606bb 100644
--- a/game/modules/tome/data/talents/chronomancy/speed-control.lua
+++ b/game/modules/tome/data/talents/chronomancy/speed-control.lua
@@ -26,17 +26,19 @@ newTalent{
 	points = 5,
 	mode = "passive",
 	getSpeed = function(self, t) return self:combatTalentScale(t, 10, 30)/100 end,
-	doCelerity = function(self, t, x, y)
-		if self.x ~= x or self.y ~= x then
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 1, 2))) end,
+	callbackOnMove = function(self, t, moved, force, ox, oy)
+		if moved and ox and oy and (ox ~= self.x or oy ~= self.y) then
+			if self.turn_procs.celerity then return end
 			local speed = t.getSpeed(self, t)
-			self:setEffect(self.EFF_CELERITY, 1, {speed=speed, charges=1, max_charges=3})
+			self:setEffect(self.EFF_CELERITY, t.getDuration(self, t), {speed=speed, charges=1, max_charges=3})
+			self.turn_procs.celerity = true
 		end
-		return true
 	end,
 	info = function(self, t)
 		local speed = t.getSpeed(self, t) * 100
-		return ([[When you move you gain %d%% movement speed for one turn.  This effect stacks up to three times.
-		]]):format(speed)
+		local duration = t.getDuration(self, t)
+		return ([[When you move you gain %d%% movement speed for %d turns.  This effect stacks up to three times but can only occur once per turn.]]):format(speed, duration)
 	end,
 }
 
@@ -45,63 +47,22 @@ newTalent{
 	type = {"chronomancy/speed-control",2},
 	require = chrono_req2,
 	points = 5,
-	sustain_paradox = 36,
-	mode = "sustained",
-	no_sustain_autoreset = true,
-	cooldown = 12,
-	tactical = { ATTACKAREA = 1, DISABLE = 3 },
-	range = 0,
-	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
-	getSlow = function(self, t) return paradoxTalentScale(self, t, 20, 40, 60)/100 end,
-	target = function(self, t)
-		return {type="ball", range=self:getTalentRange(t), friendlyfire=false, radius = self:getTalentRadius(t), talent=t}
-	end,
-	iconOverlay = function(self, t, p)
-		local val = p.charges or 0
-		if val <= 0 then return "" end
-		local fnt = "buff_font"
-		return tostring(math.ceil(val)), fnt
-	end,
-	callbackOnActBase = function(self, t)
-		local p = self:isTalentActive(t.id)
-		-- If we moved lower the power
-		if self.x ~= p.x or self.y ~= p.y then
-			p.x = self.x; p.y=self.y; p.charges = math.max(0, p.charges - 1)
-		-- Otherwise increase it
-		else
-			p.charges = math.min(p.charges + 1, 3)
-		end
-		
-		-- Dilate Time
-		if p.charges > 0 and not self.resting then
-			self:project(self:getTalentTarget(t), self.x, self.y, function(px, py)
-				local target = game.level.map(px, py, Map.ACTOR)
-				if not target then return end
-				target:setEffect(target.EFF_SLOW, 1, {power=p.power*p.charges, apply_power=getParadoxSpellpower(self, t), no_ct_effect=true})		
-			end)
+	mode = "passive",
+	getSpeed = function(self, t) return self:combatTalentScale(t, 10, 30)/200 end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 1, 2))) end,
+	callbackOnTalentPost = function(self, t,  ab)
+		if ab.type[1]:find("^chronomancy/") then
+			if self.turn_procs.time_dilation then return end
+			local speed = t.getSpeed(self, t)
+			self:setEffect(self.EFF_TIME_DILATION, t.getDuration(self, t), {speed=speed, charges=1, max_charges=3})
+			self.turn_procs.time_dilation = true
 		end
 	end,
-	updateOnTeleport = function(self, t, x, y)
-		local p = self:isTalentActive(self.T_TIME_DILATION)
-		p.x, p.y = x, y
-	end,
-	activate = function(self, t)
-		local ret ={
-			x = self.x, y=self.y, power = t.getSlow(self, t)/3, charges = 0
-		}
-		game:playSoundNear(self, "talents/arcane")
-		return ret
-	end,
-	deactivate = function(self, t, p)
-	--	self:removeParticles(p.particle)
-		return true	
-	end,
 	info = function(self, t)
-		local slow = t.getSlow(self, t) * 100
-		local radius = self:getTalentRadius(t)
-		return ([[Time Dilates around you, reducing the speed of all enemies within a radius of %d by up to %d%%.  This effect builds gradually over three turns and loses %d%% power each time you move.
-		Movement via teleport will not lower the power and the speed decrease will scale with your Spellpower.]]):
-		format(radius, slow, slow/3)
+		local speed = t.getSpeed(self, t) * 100
+		local duration = t.getDuration(self, t)
+		return ([[When you use a chronomancy spell you gain %d%% attack, spell, and mind speed for %d turns.  This effect stacks up to three times but can only occur once per turn.
+		]]):format(speed, duration)
 	end,
 }
 
@@ -113,23 +74,19 @@ newTalent{
 	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
 	cooldown = 24,
 	tactical = { BUFF = 2, CLOSEIN = 2, ESCAPE = 2 },
-	getPower= function(self, t) return paradoxTalentScale(self, t, 20, 40, 60)/300 end,
+	getSpeed = function(self, t) return self:combatTalentScale(t, 10, 30)/100 end,
 	getDuration = function(self, t) return getExtensionModifier(self, t, 4) end,
 	no_energy = true,
 	action = function(self, t)
-		local celerity = self:hasEffect(self.EFF_CELERITY) and self:hasEffect(self.EFF_CELERITY).charges or 0
-		local dilation = self:isTalentActive(self.T_TIME_DILATION) and self:isTalentActive(self.T_TIME_DILATION).charges or 0
-		local move = t.getPower(self, t) * celerity
-		local speed = t.getPower(self, t) * dilation
+		self:setEffect(self.EFF_HASTE, t.getDuration(self, t), {power=t.getSpeed(self, t)})
 		
-		self:setEffect(self.EFF_HASTE, t.getDuration(self, t), {move=move, speed=speed})
+		game:playSoundNear(self, "talents/heal")
 		return true
 	end,
 	info = function(self, t)
 		local duration = t.getDuration(self, t)
-		local power = t.getPower(self, t) * 100
-		return ([[Increases your movement speed by %d%% per stack of Celerity and your attack, spell, and mind speed by %d%% per stack of Time Dilation for the next %d game turns.
-		The speed increase will scale with your Spellpower.]]):format(power, power, duration)
+		local speed = t.getSpeed(self, t) * 100
+		return ([[Increases your global speed by %d%% for %d game turns.]]):format(speed, duration)
 	end,
 }
 
@@ -142,29 +99,20 @@ newTalent{
 	cooldown = function(self, t) return math.ceil(self:combatTalentLimit(t, 10, 45, 25)) end, -- Limit >10
 	tactical = { BUFF = 2, CLOSEIN = 2, ESCAPE = 2 },
 	no_energy = true,
-	on_pre_use = function(self, t, silent)
-		local time_dilated = false
-		if self:isTalentActive(self.T_TIME_DILATION) then
-			local p = self:isTalentActive(self.T_TIME_DILATION)
-			if p.charges == 3 then
-				time_dilated = true
-			end
-		end
-		if not time_dilated then if not silent then game.logPlayer(self, "Time must be fully dilated in order to cast time stop.") end return false end return true 
-	end,
-	getReduction = function(self, t) return 80 - paradoxTalentScale(self, t, 0, 20, 40) end,
-	getDuration = function(self, t) return getExtensionModifier(self, t, 2) end,
+	no_npc_use = true,
+	getReduction = function(self, t) return 100 end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentLimit(t, 4, 1, 3))) end,
 	action = function(self, t)
 		self.energy.value = self.energy.value + (t.getDuration(self, t) * 1000)
-		self:setEffect(self.EFF_TIME_STOP, 1, {power=t.getReduction(self, t)})
+		self:setEffect(self.EFF_TIME_STOP, 1, {power=100})
+		
 		game.logSeen(self, "#STEEL_BLUE#%s has stopped time!#LAST#", self.name:capitalize())
+		game:playSoundNear(self, "talents/heal")
 		return true
 	end,
 	info = function(self, t)
 		local duration = t.getDuration(self, t)
 		local reduction = t.getReduction(self, t)
-		return ([[Gain %d turns.  During this time your damage will be reduced by %d%%.
-		Time must be fully dilated in order to use this talent.
-		The damage reduction penalty will be lessened by your Spellpower.]]):format(duration, reduction)
+		return ([[Gain %d turns.  During this time your damage will be reduced by %d%%.]]):format(duration, reduction)
 	end,
 }
diff --git a/game/modules/tome/data/talents/chronomancy/spellbinding.lua b/game/modules/tome/data/talents/chronomancy/spellbinding.lua
index 8787a05ec90ea1f45a684d4e466e019aadb0bef3..326c6b4a799b855cbdd4a5717c8f0b7a861da352 100644
--- a/game/modules/tome/data/talents/chronomancy/spellbinding.lua
+++ b/game/modules/tome/data/talents/chronomancy/spellbinding.lua
@@ -35,6 +35,8 @@ newTalent{
 	activate = function(self, t)
 		local talent = self:talentDialog(require("mod.dialogs.talents.ChronomancyEmpower").new(self))
 		if not talent then return nil end
+		
+		game:playSoundNear(self, "talents/spell_generic")
 
 		return {
 			talent = talent, rest_count = 0
@@ -47,6 +49,7 @@ newTalent{
 		local power = t.getPower(self, t) * 100
 		local talent = self:isTalentActive(t.id) and self:getTalentFromId(self:isTalentActive(t.id).talent).name or "None"
 		return ([[Empowers the selected chronomancy spell, increasing spellpower when casting it by %d%%.
+		Each spell can only be spellbound in one way at a time.
 		
 		Current Empowered Spell: %s]]):
 		format(power, talent)
@@ -69,6 +72,8 @@ newTalent{
 	activate = function(self, t)
 		local talent = self:talentDialog(require("mod.dialogs.talents.ChronomancyExtension").new(self))
 		if not talent then return nil end
+		
+		game:playSoundNear(self, "talents/spell_generic")
 				
 		return {
 			talent = talent, rest_count = 0
@@ -81,6 +86,7 @@ newTalent{
 		local power = t.getPower(self, t) * 100
 		local talent = self:isTalentActive(t.id) and self:getTalentFromId(self:isTalentActive(t.id).talent).name or "None"
 		return ([[Extends the duration of the selected chronomancy spell by %d%%.
+		Each spell can only be spellbound in one way at a time.
 		
 		Current Extended Spell: %s]]):
 		format(power, talent)
@@ -103,7 +109,9 @@ newTalent{
 	activate = function(self, t)
 		local talent = self:talentDialog(require("mod.dialogs.talents.ChronomancyMatrix").new(self))
 		if not talent then return nil end
-				
+		
+		game:playSoundNear(self, "talents/spell_generic")
+		
 		return {
 			talent = talent, rest_count = 0
 		}
@@ -115,6 +123,7 @@ newTalent{
 		local power = t.getPower(self, t) * 100
 		local talent = self:isTalentActive(t.id) and self:getTalentFromId(self:isTalentActive(t.id).talent).name or "None"
 		return ([[Reduces the cooldown of the selected chronomancy spell by %d%%.
+		Each spell can only be spellbound in one way at a time.
 		
 		Current Matrix Spell: %s]]):
 		format(power, talent)
@@ -137,6 +146,8 @@ newTalent{
 	activate = function(self, t)
 		local talent = self:talentDialog(require("mod.dialogs.talents.ChronomancyQuicken").new(self))
 		if not talent then return nil end
+		
+		game:playSoundNear(self, "talents/spell_generic")
 				
 		return {
 			talent = talent, rest_count = 0
@@ -149,6 +160,7 @@ newTalent{
 		local power = t.getPower(self, t) * 100
 		local talent = self:isTalentActive(t.id) and self:getTalentFromId(self:isTalentActive(t.id).talent).name or "None"
 		return ([[Reduces the casting speed of the selected chronomancy spell by %d%%.
+		Each spell can only be spellbound in one way at a time.
 		
 		Current Quickened Spell: %s]]):
 		format(power, talent)
diff --git a/game/modules/tome/data/talents/chronomancy/stasis.lua b/game/modules/tome/data/talents/chronomancy/stasis.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2facff28fa4dbaf46c687fdc0c10e8d66e30cfdc
--- /dev/null
+++ b/game/modules/tome/data/talents/chronomancy/stasis.lua
@@ -0,0 +1,159 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009 - 2015 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
+
+-- EDGE TODO: Particles, Timed Effect Particles
+
+newTalent{
+	name = "Spacetime Stability",
+	type = {"chronomancy/stasis", 1},
+	require = chrono_req1,
+	mode = "passive",
+	points = 5,
+	getWilMult = function(self, t) return self:combatTalentScale(t, 0.15, 0.5) end,
+	getTuningAdjustment= function(self, t) return math.floor(self:combatTalentScale(t, 2, 8, "log")) end,
+	passives = function(self, t, p)
+		self:talentTemporaryValue(p, "paradox_will_multi", t.getWilMult(self, t))
+	end,
+	info = function(self, t)
+		local will = t.getWilMult(self, t)
+		local duration = t.getTuningAdjustment(self, t)
+		return ([[You've learned to focus your control over the spacetime continuum, and quell anomalous effects.  Increases your Willpower for determing modified Paradox by %d%%.
+		Additionally reduces the time it takes you to adjust your Paradox with Spacetime Tuning by %d turns.]]):
+		format(will * 100, duration)
+	end,
+}
+
+newTalent{
+	name = "Time Shield", short_name = "CHRONO_TIME_SHIELD",
+	type = {"chronomancy/stasis",2},
+	require = chrono_req2,
+	points = 5,
+	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
+	cooldown = 18,
+	tactical = { DEFEND = 2 },
+	range = 10,
+	no_energy = true,
+	getMaxAbsorb = function(self, t) return 50 + self:combatTalentSpellDamage(t, 50, 450, getParadoxSpellpower(self, t)) end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, util.bound(5 + math.floor(self:getTalentLevel(t)), 5, 15)) end,
+	getTimeReduction = function(self, t) return 25 + util.bound(15 + math.floor(self:getTalentLevel(t) * 2), 15, 35) end,
+	action = function(self, t)
+		self:setEffect(self.EFF_TIME_SHIELD, t.getDuration(self, t), {power=t.getMaxAbsorb(self, t), dot_dur=5, time_reducer=t.getTimeReduction(self, t)})
+		game:playSoundNear(self, "talents/spell_generic")
+		return true
+	end,
+	info = function(self, t)
+		local maxabsorb = t.getMaxAbsorb(self, t)
+		local duration = t.getDuration(self, t)
+		local time_reduc = t.getTimeReduction(self,t)
+		return ([[This intricate spell instantly erects a time shield around the caster, preventing any incoming damage and sending it forward in time.
+		Once either the maximum damage (%d) is absorbed, or the time runs out (%d turns), the stored damage will return as a temporal restoration field over time (5 turns).
+		Each turn the restoration field is active, you get healed for 10%% of the absorbed damage.
+		While under the effect of Time Shield, all newly applied magical, physical and mental effects will have their durations reduced by %d%%.
+		The shield's max absorption will increase with your Spellpower.]]):
+		format(maxabsorb, duration, time_reduc)
+	end,
+}
+
+newTalent{
+	name = "Stop",
+	type = {"chronomancy/stasis",3},
+	require = chrono_req3,
+	points = 5,
+	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
+	cooldown = 8,
+	tactical = { ATTACKAREA = 1, DISABLE = 3 },
+	range = 10,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 1.3, 2.7)) end,
+	direct_hit = true,
+	requires_target = true,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
+	end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.ceil(self:combatTalentScale(t, 2.3, 4.3))) end,
+	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 220, getParadoxSpellpower(self, t)) end,
+	action = function(self, t)
+		local tg = self:getTalentTarget(t)
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		local _ _, _, _, x, y = self:canProject(tg, x, y)
+		
+		local dam = self:spellCrit(t.getDamage(self, t))
+		local dur = t.getDuration(self, t)
+		
+		local grids = self:project(tg, x, y, function(px, py)
+			local target = game.level.map(px, py, Map.ACTOR)
+			if target then
+				self:project({type="hit"}, px, py, DamageType.TEMPORAL, dam)
+				
+				-- Apply Stun or Time Prison
+				if self:hasEffect(self.EFF_STATIC_HISTORY) then
+					-- Freeze it, if we pass the test
+					local sx, sy = game.level.map:getTileToScreen(px, py)
+					local hit = self:checkHit(getParadoxSpellpower(self, t) - (target:attr("continuum_destabilization") or 0), target:combatSpellResist(), 0, 95, 15)
+					if hit then
+						if target ~= self then target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=getParadoxSpellpower(self, t, 0.3), no_ct_effect=true}) end
+						target:setEffect(target.EFF_TIME_PRISON, dur, {})
+					else
+						game.logSeen(target, "%s resists the time prison.", target.name:capitalize())
+					end
+				elseif target:canBe("stun") then
+					target:setEffect(target.EFF_STUNNED, dur, {apply_power=getParadoxSpellpower(self, t)})
+				end
+			end
+		end)
+		
+		game.level.map:particleEmitter(x, y, tg.radius, "temporal_flash", {radius=tg.radius, tx=x, ty=y})
+		game:playSoundNear(self, "talents/tidalwave")
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		local radius = self:getTalentRadius(t)
+		local duration = t.getDuration(self, t)
+		return ([[Inflicts %0.2f temporal damage, and attempts to stun all other creatures in a radius %d ball for %d turns.
+		The damage will scale with your Spellpower.]]):
+		format(damDesc(self, DamageType.TEMPORAL, damage), radius, duration)
+	end,
+}
+
+newTalent{
+	name = "Static History",
+	type = {"chronomancy/stasis",4},
+	require = chrono_req4,
+	points = 5,
+	cooldown = 24,
+	tactical = { PARADOX = 2 },
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 3.5, 8.5))) end,
+	getParadoxMulti = function(self, t) return self:combatTalentLimit(t, 1, 0.2, .60) end, -- limit 100%
+	no_energy = true,
+	action = function(self, t)
+		self:setEffect(self.EFF_STATIC_HISTORY, t.getDuration(self, t), {power=t.getParadoxMulti(self, t)})
+		
+		game:playSoundNear(self, "talents/spell_generic")
+		return true
+	end,
+	info = function(self, t)
+		local multi = t.getParadoxMulti(self, t) * 100
+		local duration = t.getDuration(self, t)
+		return ([[For the next %d turns Stop will remove affected targets from the flow of time rather than stunning them.  In this state, the target can neither act nor be harmed.
+		Time does not pass at all for the target, no talents will cooldown, no resources will regen, and so forth.
+		Additionally all your chronomancy spells cost %d%% less Paradox while this effect is active.]]):
+		format(duration, multi)
+	end,
+}
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/chronomancy/temporal-combat.lua b/game/modules/tome/data/talents/chronomancy/temporal-combat.lua
index 720fe1b36809f9296b62d484e931475586b9fb35..792d8883b03ccef3a360e16f4716d0e025b35bd1 100644
--- a/game/modules/tome/data/talents/chronomancy/temporal-combat.lua
+++ b/game/modules/tome/data/talents/chronomancy/temporal-combat.lua
@@ -16,3 +16,317 @@
 --
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
+
+-- some helpers
+
+local function cooldown_folds(self, t)
+	for tid, cd in pairs(self.talents_cd) do
+		local tt = self:getTalentFromId(tid)
+		if tt.type[1]:find("^chronomancy/manifold") and t ~= tt then
+			self:alterTalentCoolingdown(tt, -1)
+		end
+	end
+end
+
+local function do_folds(self, target)
+	for tid, _ in pairs(self.talents) do
+		local tt = self:getTalentFromId(tid)
+		if tt.type[1]:find("^chronomancy/manifold") and self:knowTalent(tid) then
+			self:callTalent(tid, "doFold", target)
+		end
+	end
+end
+
+newTalent{
+	name = "Fold Fate",
+	type = {"chronomancy/manifold", 1},
+	cooldown = 8,
+	points = 5,
+	mode = "passive",
+	range = 10,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t}
+	end,
+	radius = function(self, t) return self:getTalentLevel(t) >= 4 and 2 or 1 end,
+	getChance = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getChance") end, 
+	getDamage = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getDamage") end,
+	doFold = function(self, t, target)
+		if rng.percent(t.getChance(self, t)) then
+			if not self:isTalentCoolingDown(t.id) then
+				-- Temporal Burst
+				local tgts = 0
+				local tg = self:getTalentTarget(t)
+				self:project(tg, target.x, target.y, function(px, py, tg, self)
+					local target = game.level.map(px, py, Map.ACTOR)
+					if target then
+						DamageType:get(DamageType.TEMPORAL).projector(self, target.x, target.y, DamageType.TEMPORAL, t.getDamage(self, t))
+					end
+				end)
+				
+				self.energy.value = self.energy.value + (tgts*100)
+				self:startTalentCooldown(t.id)
+				game.level.map:particleEmitter(target.x, target.y, tg.radius, "generic_sploom", {rm=230, rM=255, gm=230, gM=255, bm=30, bM=51, am=35, aM=90, radius=tg.radius, basenb=120})
+			else
+				cooldown_folds(self, t)
+			end
+		end	
+	end,
+	info = function(self, t)
+		local chance = t.getChance(self, t)
+		local damage = t.getDamage(self, t)
+		local radius = self:getTalentRadius(t)
+		return ([[When you hit with Weapon Folding you have a %d%% chance of dealing an additional %0.2f temporal damage to enemies in a radius of %d.  For each target hit you gain 10%% of a turn.
+		This effect has a cooldown.  If it triggers while on cooldown it will reduce the cooldown of Fold Gravity and Fold Warp by one turn.]])
+		:format(chance, damDesc(self, DamageType.TEMPORAL, damage), radius)
+	end,
+}
+
+newTalent{
+	name = "Fold Warp",
+	type = {"chronomancy/manifold", 1},
+	cooldown = 8,
+	points = 5,
+	mode = "passive",
+	range = 10,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t}
+	end,
+	radius = function(self, t) return self:getTalentLevel(t) >= 4 and 2 or 1 end,
+	getChance = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getChance") end, 
+	getDamage = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getDamage") end,
+	getDuration = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getDuration") end,
+	doFold = function(self, t, target)
+		if rng.percent(t.getChance(self, t)) then
+			if not self:isTalentCoolingDown(t.id) then
+				-- Warp Burst
+				local tgts = 0
+				local tg = self:getTalentTarget(t)
+				self:project(tg, target.x, target.y, function(px, py, tg, self)
+					local target = game.level.map(px, py, Map.ACTOR)
+					if target then
+						DamageType:get(DamageType.WARP).projector(self, target.x, target.y, DamageType.WARP, t.getDamage(self, t))
+						randomWarpEffect(self, t, target)
+					end
+				end)
+				
+				self:startTalentCooldown(t.id)
+				game.level.map:particleEmitter(target.x, target.y, tg.radius, "generic_sploom", {rm=64, rM=64, gm=134, gM=134, bm=170, bM=170, am=35, aM=90, radius=tg.radius, basenb=120})
+			else
+				cooldown_folds(self, t)
+			end
+		end	
+	end,
+	info = function(self, t)
+		local chance = t.getChance(self, t)
+		local damage = t.getDamage(self, t)
+		local radius = self:getTalentRadius(t)
+		local duration = t.getDuration(self, t)
+		return ([[When you hit with Weapon Folding you have a %d%% chance of dealing an additional %0.2f physical and %0.2f temporal (warp) damage to enemies in a radius of %d.
+		Each target hit may be stunned, blinded, pinned, or confused for %d turns.
+		This effect has a cooldown.  If it triggers while on cooldown it will reduce the cooldown of Fold Gravity and Fold Fate by one turn.]])
+		:format(chance, damDesc(self, DamageType.TEMPORAL, damage/2), damDesc(self, DamageType.PHYSICAL, damage/2), radius, duration)
+	end,
+}
+
+newTalent{
+	name = "Fold Gravity",
+	type = {"chronomancy/manifold", 1},
+	cooldown = 8,
+	points = 5,
+	mode = "passive",
+	range = 10,
+	radius = function(self, t) return self:getTalentLevel(t) >= 4 and 2 or 1 end,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t}
+	end,
+	getChance = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getChance") end, 
+	getDamage = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getDamage") end,
+	getDuration = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getDuration") end,
+	getSlow = function(self, t) return self:callTalent(self.T_WEAPON_MANIFOLD, "getSlow") end,
+	doFold = function(self, t, target)
+		if rng.percent(t.getChance(self, t)) then
+			if not self:isTalentCoolingDown(t.id) then
+				-- Gravity Burst
+				local tg = self:getTalentTarget(t)
+				self:project(tg, target.x, target.y, function(px, py, tg, self)
+					local target = game.level.map(px, py, Map.ACTOR)
+					if target then
+						target:setEffect(target.EFF_SLOW, t.getDuration(self, t), {power=t.getSlow(self, t)/100, apply_power=getParadoxSpellpower(self, t), no_ct_effect=true})
+						DamageType:get(DamageType.GRAVITY).projector(self, target.x, target.y, DamageType.GRAVITY, t.getDamage(self, t))
+					end
+				end)
+				
+				self:startTalentCooldown(t.id)
+				game.level.map:particleEmitter(target.x, target.y, tg.radius, "generic_sploom", {rm=205, rM=205, gm=133, gM=133, bm=63, bM=63, am=35, aM=90, radius=tg.radius, basenb=120})
+			else
+				cooldown_folds(self, t)
+			end
+		end	
+	end,
+	info = function(self, t)
+		local chance = t.getChance(self, t)
+		local damage = t.getDamage(self, t)
+		local radius = self:getTalentRadius(t)
+		local slow = t.getSlow(self, t)
+		local duration = t.getDuration(self, t)
+		return ([[When you hit with Weapon Folding you have a %d%% chance of dealing an additional %0.2f physical (gravity) damage to enemies in a radius of %d.
+		Affected targets may also be slowed, decreasing their global speed speed by %d%% for %d turns
+		This effect has a cooldown.  If it triggers while on cooldown it will reduce the cooldown of Fold Fate and Fold Warp by one turn.]])
+		:format(chance, damDesc(self, DamageType.PHYSICAL, damage), radius, slow, duration)
+	end,
+}
+
+newTalent{
+	name = "Weapon Folding",
+	type = {"chronomancy/temporal-combat", 1},
+	mode = "sustained",
+	require = chrono_req1,
+	sustain_paradox = 12,
+	cooldown = 10,
+	tactical = { BUFF = 2 },
+	points = 5,
+	activate = function(self, t)
+		game:playSoundNear(self, "talents/spell_generic")
+		
+		return {}
+	end,
+	deactivate = function(self, t, p)
+		return true
+	end,
+	getDamage = function(self, t) return 7 + getParadoxSpellpower(self, t, 0.092) * self:combatTalentScale(t, 1, 7) end,
+	doWeaponFolding = function(self, t, target)  
+		local dam = t.getDamage(self, t)
+		do_folds(self, target)
+		if not target.dead then
+			DamageType:get(DamageType.TEMPORAL).projector(self, target.x, target.y, DamageType.TEMPORAL, dam)
+		end
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		return ([[Folds a single dimension of your weapons (or ammo) upon itself, adding %0.2f temporal damage to your strikes and increasing your armor penetration by %d.
+		The armor penetration and damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.TEMPORAL, damage), damage/2)
+	end,
+}
+
+newTalent{
+	name = "Invigorate",
+	type = {"chronomancy/temporal-combat", 2},
+	require = chrono_req2,
+	points = 5,
+	paradox = function (self, t) return getParadoxCost(self, t, 24) end,
+	cooldown = 24,
+	fixed_cooldown = true,
+	tactical = { HEAL = 1 },
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentLimit(t, 14, 4, 8))) end, -- Limit < 14
+	getPower = function(self, t) return self:combatTalentSpellDamage(t, 10, 50, getParadoxSpellpower(self, t)) end,
+	action = function(self, t)
+		self:setEffect(self.EFF_INVIGORATE, t.getDuration(self,t), {power=t.getPower(self, t)})
+		
+		game:playSoundNear(self, "talents/heal")
+		return true
+	end,
+	info = function(self, t)
+		local power = t.getPower(self, t)
+		local duration = t.getDuration(self, t)
+		return ([[For the next %d turns, you recover %0.1f life and %0.1f stamina per turn, and most other talents on cooldown will refresh twice as fast as usual.
+		The life and stamina regeneration will increase with your Spellpower.]]):format(duration, power, power/2)
+	end,
+}
+
+newTalent{
+	name = "Weapon Manifold",
+	type = {"chronomancy/temporal-combat", 3},
+	require = chrono_req3,
+	mode = "passive",
+	points = 5,
+	cooldown = 8,
+	on_learn = function(self, t)
+		local lev = self:getTalentLevelRaw(t)
+		if lev == 1 then
+			self:learnTalent(Talents.T_FOLD_FATE, true, nil, {no_unlearn=true})
+			self:learnTalent(Talents.T_FOLD_GRAVITY, true, nil, {no_unlearn=true})
+			self:learnTalent(Talents.T_FOLD_WARP, true, nil, {no_unlearn=true})
+		end
+	end,
+	on_unlearn = function(self, t)
+		local lev = self:getTalentLevelRaw(t)
+		if lev == 0 then
+			self:unlearnTalent(Talents.T_FOLD_FATE)
+			self:unlearnTalent(Talents.T_FOLD_GRAVITY)
+			self:unlearnTalent(Talents.T_FOLD_WARP)
+		end
+	end,
+	radius = function(self, t) return self:getTalentLevel(t) >= 4 and 2 or 1 end,
+	getDuration = function(self, t) return 4 end,
+	getDamage = function(self, t) return 7 + getParadoxSpellpower(self, t, 0.092) * self:combatTalentScale(t, 1, 7) end,
+	getChance = function(self, t) return self:combatTalentLimit(t, 40, 10, 30) end,
+	getSlow = function(self, t) return 30 end,
+	info = function(self, t)
+		local chance = t.getChance(self, t)
+		local damage = t.getDamage(self, t)
+		local radius = self:getTalentRadius(t)
+		local slow = t.getSlow(self, t)
+		local duration = t.getDuration(self, t)
+		return ([[You now have a %d%% chance to Fold Fate, Gravity, or Warp into your Weapon Folding damage.
+		
+		Fold Fate: Deals %0.2f temporal damage to enemies in a radius of %d.  For each enemy hit you gain 10%% of a turn.
+		Fold Warp: Deals %0.2f physical and %0.2f temporal damage to enemies in a radius of %d.  Affected targets may be stunned, blinded, confused, or pinned for %d turns.
+		Fold Gravity: Deals %0.2f physical damage to enemies in a radius of %d.  Affected targets will be slowed (%d%%) for %d turns.
+		
+		Each Fold has an eight turn cooldown.  If an effect would be triggered while on cooldown it will reduce the cooldown of the other two Folds by one turn.]]
+		):format(chance, damDesc(self, DamageType.TEMPORAL, damage), radius, damDesc(self, DamageType.PHYSICAL, damage/2), damDesc(self, DamageType.TEMPORAL, damage/2), radius,
+		duration, damDesc(self, DamageType.PHYSICAL, damage), radius, slow, duration)
+	end,
+}
+
+newTalent{
+	name = "Breach",
+	type = {"chronomancy/temporal-combat", 4},
+	require = chrono_req4,
+	points = 5,
+	cooldown = 8,
+	paradox = function (self, t) return getParadoxCost(self, t, 12) end,
+	tactical = { ATTACK = {weapon = 2}, DISABLE = 3 },
+	requires_target = true,
+	range = function(self, t)
+		if self:hasArcheryWeapon() then return util.getval(archery_range, self, t) end
+		return 1
+	end,
+	is_melee = function(self, t) return not self:hasArcheryWeapon() end,
+	speed = function(self, t) return self:hasArcheryWeapon() and "archery" or "weapon" end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 3, 7))) end,
+	on_pre_use = function(self, t, silent) if self:attr("disarmed") then if not silent then game.logPlayer(self, "You require a weapon to use this talent.") end return false end return true end,
+	archery_onhit = function(self, t, target, x, y)
+		target:setEffect(target.EFF_BREACH, t.getDuration(self, t), {})
+	end,
+	action = function(self, t)
+
+		if self:hasArcheryWeapon() then
+			-- Ranged attack
+			local targets = self:archeryAcquireTargets({type="bolt"}, {one_shot=true, no_energy = true})
+			if not targets then return end
+			self:archeryShoot(targets, t, {type="bolt"}, {mult=t.getDamage(self, t)})
+		else
+			-- Melee attack
+			local tg = {type="hit", range=self:getTalentRange(t), talent=t}
+			local x, y, target = self:getTarget(tg)
+			if not target or not self:canProject(tg, x, y) then return nil end
+			local hitted = self:attackTarget(target, nil, t.getDamage(self, t), true)
+
+			if hitted then
+				target:setEffect(target.EFF_BREACH, t.getDuration(self, t), {apply_power=getParadoxSpellpower(self, t)})
+			end
+		end
+
+		return true
+	end,
+	info = function(self, t)
+		local duration = t.getDuration(self, t)
+		local damage = t.getDamage(self, t) * 100
+		return ([[Attack the target with either your ranged or melee weapons for %d%% damage.
+		If the attack hits you'll breach the target's immunities, reducing armor hardiness, stun, pin, blindness, and confusion immunity by 50%% for %d turns.
+		Breach chance scales with your Spellpower.]])
+		:format(damage, duration)
+	end
+}
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/chronomancy/temporal-hounds.lua b/game/modules/tome/data/talents/chronomancy/temporal-hounds.lua
index ae1a208052d44a53ddf76903e64a9003185b84cf..465a73b6663b64e8d656b1f03a0c10e88bf67073 100644
--- a/game/modules/tome/data/talents/chronomancy/temporal-hounds.lua
+++ b/game/modules/tome/data/talents/chronomancy/temporal-hounds.lua
@@ -22,6 +22,7 @@
 -- Ode to Angband/Tome 2 and all the characters I lost to Time Hounds
 summonTemporalHound = function(self, t)  
 	if game.zone.wilderness then return false end
+	if self.summoner then return false end
 	
 	local x, y = util.findFreeGrid(self.x, self.y, 8, true, {[Map.ACTOR]=true})
 	if not x then
@@ -178,15 +179,11 @@ newTalent{
 		summonTemporalHound(self, t)
 		
 		return {
-				-- Turn off friendly fire if we have this sustain; thanks dekar for the idea :)
-				proj = self:addTemporaryValue("archery_pass_friendly", 1),
 				rest_count = self:getTalentCooldown(t), 
 				hounds = 1, max_hounds = 3
 		}
 	end,
 	deactivate = function(self, t, p)
-		self:removeTemporaryValue("archery_pass_friendly", p.proj)
-		
 		-- unsummon the hounds :(
 		for _, e in pairs(game.level.entities) do
 			if e.summoner and e.summoner == self and e.name == "temporal hound" then
@@ -201,8 +198,7 @@ newTalent{
 		local resists = t.getResists(self, t)
 		return ([[Upon activation summon a Temporal Hound.  Every %d turns another hound will be summoned, up to a maximum of three hounds. If a hound dies you'll summon a new hound in %d turns.  
 		Your hounds inherit your increased damage percent and have %d%% physical resistance and %d%% temporal resistance.
-		Hounds will get, %d Strength, %d Dexterity, %d Constitution, %d Magic, %d Willpower, and %d Cunning ,based on your Spellpower.
-		While Temporal Hounds is active your arrows will shoot through friendly targets.]])
+		Hounds will get, %d Strength, %d Dexterity, %d Constitution, %d Magic, %d Willpower, and %d Cunning ,based on your Spellpower.]])
 		:format(cooldown, cooldown, resists/2, math.min(100, resists*2), incStats.str + 1, incStats.dex + 1, incStats.con + 1, incStats.mag + 1, incStats.wil +1, incStats.cun + 1)
 	end
 }
@@ -292,7 +288,7 @@ newTalent{
 	end,
 	info = function(self, t)
 		local defense = t.getDefense(self, t)
-		return ([[Command your Temporal Hounds to teleport to the targeted location.  If you target a creature with this effect your hounds will set that creature as their target.
+		return ([[Command your Temporal Hounds to teleport to the targeted location.  If you target an enemy your hounds will set that enemy as their target.
 		When you learn this talent, your hounds gain %d defense and %d%% resist all after any teleport.
 		At talent level five, if you're not at your maximum number of hounds when you cast this spell a new one will be summoned.
 		The teleportation bonuses scale with your Spellpower.]]):format(defense, defense, defense/2, defense/2)
@@ -309,7 +305,7 @@ newTalent{
 		return self:combatTalentLimit(t, 1, 0.15, 0.50) -- Limit <100%
 	end,
 	getRegen = function(self, t) return self:combatTalentSpellDamage(t, 10, 50, getParadoxSpellpower(self, t)) end,
-	getHaste = function(self, t) return paradoxTalentScale(self, t, 20, 50, 80)/100 end,
+	getHaste = function(self, t) return self:combatTalentLimit(t, 80, 20, 50)/100 end,
 	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 2, 6))) end,
 	doBlink = function(self, t, hound)  -- Triggered when the hounds is hit
 		local regen, haste = t.getRegen(self, t), t.getHaste(self, t)
@@ -334,7 +330,7 @@ newTalent{
 		return ([[Your hounds can now survive for up to %d turns after their hit points are reduced below 1.  While in this state they deal 50%% less damage but are immune to additional damage.
 		Command Blink will now regenerate your hounds for %d life per turn and increase their global speed by %d%% for five turns.  Hounds below 1 life when this effect occurs will have the bonuses doubled.
 		When you learn this talent, your hounds gain %d%% stun, blind, confusion, and pin resistance.
-		The regeneration and haste effects scale with your Spellpower.]]):format(duration, regen, haste, immunities)
+		The regeneration scales with your Spellpower.]]):format(duration, regen, haste, immunities)
 	end
 }
 
@@ -398,12 +394,14 @@ newTalent{
 			local dam = a:spellCrit(t.getDamage(self, t)) -- hound crit but our spellpower, mostly so it looks right
 			
 			a:project(tg, x, y, function(px, py)
-				DamageType:get(DamageType.TEMPORAL).projector(a, px, py, DamageType.TEMPORAL, dam)
-				-- Don't turn back the clock other hounds
 				local target = game.level.map(px, py, Map.ACTOR)
-				if target and target.name ~= "temporal hound" then
-					target:setEffect(target.EFF_TURN_BACK_THE_CLOCK, 3, {power=t.getDamageStat(self, t), apply_power=a:combatSpellpower(), min_dur=1})
-				end	
+				if target and target ~= a.summoner then
+					DamageType:get(DamageType.TEMPORAL).projector(a, px, py, DamageType.TEMPORAL, dam)
+					-- Don't turn back the clock other hounds
+					if target.name ~= "temporal hound" then
+						target:setEffect(target.EFF_TURN_BACK_THE_CLOCK, 3, {power=t.getDamageStat(self, t), apply_power=a:combatSpellpower(), min_dur=1})
+					end
+				end
 			end)
 			
 			game.level.map:particleEmitter(a.x, a.y, tg.radius, "breath_time", {radius=tg.radius, tx=x-a.x, ty=y-a.y})
@@ -419,7 +417,7 @@ newTalent{
 		local stat_damage = t.getDamageStat(self, t)
 		local affinity = t.getResists(self, t)
 		return ([[Command your Temporal Hounds to breathe time, dealing %0.2f temporal damage and reducing the stats of all targets in a radius %d cone.
-		Affected targets will have their stats reduced by %d for 3 turns.  You are not immune to the breath of your own hounds, but your hounds are immune to stat damage from other hounds.
+		Affected targets will have their stats reduced by %d for 3 turns.  You are immune to the breath of your own hounds and your hounds are immune to stat damage from other hounds.
 		When you learn this talent, your hounds gain %d%% temporal damage affinity.]]):format(damDesc(self, DamageType.TEMPORAL, damage), radius, stat_damage, affinity)
 	end,
 }
diff --git a/game/modules/tome/data/talents/chronomancy/threaded-combat.lua b/game/modules/tome/data/talents/chronomancy/threaded-combat.lua
index 50559a98430379a7ca881c5085a0c89dfec00dc1..65aee3585539def5cd264925dce94d9192d70316 100644
--- a/game/modules/tome/data/talents/chronomancy/threaded-combat.lua
+++ b/game/modules/tome/data/talents/chronomancy/threaded-combat.lua
@@ -20,29 +20,113 @@
 -- EDGE TODO: Particles, Timed Effect Particles
 
 newTalent{
-	name = "Frayed Threads",
+	name = "Thread Walk",
 	type = {"chronomancy/threaded-combat", 1},
 	require = chrono_req_high1,
+	points = 5,
+	--cooldown = 6,
+	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
+	tactical = { ATTACK = {weapon = 2}, CLOSEIN = 2, ESCAPE = 2 },
+	requires_target = true,
+	is_teleport = true,
+	range = function(self, t)
+		if self:hasArcheryWeapon("bow") then return util.getval(archery_range, self, t) end
+		return 1
+	end,
+	is_melee = function(self, t) return not self:hasArcheryWeapon("bow") end,
+	speed = function(self, t) return self:hasArcheryWeapon("bow") and "archery" or "weapon" end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	getTeleportRange = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9, 0.5, 0, 1)) end,
+	on_pre_use = function(self, t, silent) if self:attr("disarmed") then if not silent then game.logPlayer(self, "You require a weapon to use this talent.") end return false end return true end,
+	archery_onhit = function(self, t, target, x, y)
+		local accuracy = math.max(0, 10 - t.getTeleportRange(self, t))
+		game:onTickEnd(function()
+			local tx, ty = util.findFreeGrid(x, y, 5, true, {[Map.ACTOR]=true})
+			game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
+			self:teleportRandom(tx, ty, accuracy)
+			game:playSoundNear(self, "talents/teleport")
+			game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
+		end)
+	end,
+	action = function(self, t)
+		local mainhand, offhand = self:hasDualWeapon()
+
+		if self:hasArcheryWeapon("bow") then
+			-- Ranged attack
+			local targets = self:archeryAcquireTargets({type="bolt"}, {one_shot=true, no_energy = true})
+			if not targets then return end
+			self:archeryShoot(targets, t, {type="bolt"}, {mult=t.getDamage(self, t)})
+		elseif mainhand then
+			-- Melee attack
+			local tg = {type="hit", range=self:getTalentRange(t), talent=t}
+			local x, y, target = self:getTarget(tg)
+			if not target or not self:canProject(tg, x, y) then return nil end
+			local hitted = self:attackTarget(target, nil, t.getDamage(self, t), true)
+
+				
+			if hitted then
+				-- Find our teleport location
+				local dist = t.getTeleportRange(self, t) / core.fov.distance(x, y, self.x, self.y)
+				local destx, desty = math.floor((self.x - x) * dist + x), math.floor((self.y - y) * dist + y)
+				local l = core.fov.line(x, y, destx, desty, false)
+				local lx, ly, is_corner_blocked = l:step()
+				local ox, oy
+				
+				while game.level.map:isBound(lx, ly) and not game.level.map:checkEntity(lx, ly, Map.TERRAIN, "block_move") and not is_corner_blocked do
+					if not game.level.map(lx, ly, Map.ACTOR) then ox, oy = lx, ly end
+					lx, ly, is_corner_blocked = l:step()
+				end
+				
+				game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
+				game:playSoundNear(self, "talents/teleport")
+				
+				-- ox, oy now contain the last square in line not blocked by actors.
+				if ox and oy then 
+					self:teleportRandom(ox, oy, 0)
+					game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
+				end
+
+			end
+
+		else
+			game.logPlayer(self, "You cannot use Thread Walk without an appropriate weapon!")
+			return nil
+		end
+		
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t) * 100
+		local range = t.getTeleportRange(self, t)
+		local accuracy = math.max(0, 10 - t.getTeleportRange(self, t))
+		return ([[Attack with your bow or dual-weapons for %d%% damage.
+		If you shoot an arrow you'll teleport near any target hit (radius %d accuracy).  If you hit with either of your dual-weapons you'll teleport up to %d tiles away from the target.]])
+		:format(damage, accuracy, range)
+	end
+}
+
+newTalent{
+	name = "Blended Threads",
+	type = {"chronomancy/threaded-combat", 2},
+	require = chrono_req_high2,
 	mode = "passive",
 	points = 5,
-	getPercent = function(self, t) return paradoxTalentScale(self, t, 40, 80, 100)/100 end,
-	getRadius = function(self, t) return self:getTalentLevel(t) > 4 and 2 or 1 end,
+	getPercent = function(self, t) return self:combatTalentScale(t, 10, 50)/100 end,
 	info = function(self, t)
 		local percent = t.getPercent(self, t) * 100
-		local radius = t.getRadius(self, t)
-		return ([[Your Weapon Folding and Impact spells now deal an additional %d%% damage in a radius of %d.
-		The damage percent will scale with your Spellpower.]])
-		:format(percent, radius)
+		return ([[Your Bow Threading and Blade Threading attacks now deal %d%% more weapon damage if you did not have the appropriate weapon equipped when you initiated the attack.]])
+		:format(percent)
 	end
 }
 
 newTalent{
 	name = "Thread the Needle",
-	type = {"chronomancy/threaded-combat", 2},
-	require = chrono_req_high2,
+	type = {"chronomancy/threaded-combat", 3},
+	require = chrono_req_high3,
 	points = 5,
 	cooldown = 8,
-	paradox = function (self, t) return getParadoxCost(self, t, 15) end,
+	fixed_cooldown = true,
+	paradox = function (self, t) return getParadoxCost(self, t, 18) end,
 	tactical = { ATTACKAREA = { weapon = 3 } , DISABLE = 3 },
 	requires_target = true,
 	range = function(self, t)
@@ -117,176 +201,144 @@ newTalent{
 }
 
 newTalent{
-	name = "Blended Threads",
-	type = {"chronomancy/threaded-combat", 3},
-	require = chrono_req_high3,
-	mode = "passive",
-	points = 5,
-	getPercent = function(self, t) return paradoxTalentScale(self, t, 10, 30, 50)/100 end,
-	info = function(self, t)
-		local percent = t.getPercent(self, t) * 100
-		return ([[Your Bow Threading and Blade Threading spells now deal %d%% more weapon damage if you did not have the appropriate weapon equipped when you initated the attack.
-		The damage percent will scale with your Spellpower.]])
-		:format(percent)
-	end
-}
-
-newTalent{
-	name = "Twin Threads",
+	name = "Warden's Call", short_name = WARDEN_S_CALL,
 	type = {"chronomancy/threaded-combat", 4},
 	require = chrono_req_high4,
+	mode = "passive",
 	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
-	cooldown = function(self, t) return math.ceil(self:combatTalentLimit(t, 15, 45, 25)) end, -- Limit >15
-	tactical = { ATTACK = {weapon = 4} },
-	range = 10,
-	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 6, 12))) end,
-	getDamagePenalty = function(self, t) return 60 - paradoxTalentScale(self, t, 0, 20, 30) end,
-	requires_target = true,
-	target = function(self, t)
-		return {type="hit", range=self:getTalentRange(t)}
-	end,
-	direct_hit = true,
-	remove_on_clone = true,
-	action = function(self, t)
-		local tg = self:getTalentTarget(t)
-		local x, y, target = self:getTarget(tg)
-		if not x or not y then return nil end
-		if not self:hasLOS(x, y) or game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move") then
-			game.logSeen(self, "You do not have line of sight.")
-			return nil
+	getDamagePenalty = function(self, t) return 80 - self:combatTalentLimit(t, 80, 0, 60) end,
+	doBladeWarden = function(self, t, target)
+		-- Sanity check
+		if not self.turn_procs.blade_warden then 
+			self.turn_procs.blade_warden = true
+		else
+			return
 		end
-		local __, x, y = self:canProject(tg, x, y)
-
-		-- First find a position
-		local blade_warden = false
-		local tx, ty = util.findFreeGrid(x, y, 5, true, {[Map.ACTOR]=true})
-		-- Create our melee clone
-		if tx and ty then
-			game.level.map:particleEmitter(tx, ty, 1, "temporal_teleport")
-
-			-- clone our caster
-			local m = makeParadoxClone(self, self, t.getDuration(self, t))
-
-			-- remove some talents; note most of this is handled by makeParadoxClone, but we want to be more extensive
-			local tids = {}
-			for tid, _ in pairs(m.talents) do
-				local t = m:getTalentFromId(tid)
-				local tt = self:getTalentFromId(tid)
-				if not tt.type[1]:find("^chronomancy/blade") and not tt.type[1]:find("^chronomancy/threaded") and not tt.type[1]:find("^chronomancy/guardian") then
-					tids[#tids+1] = t
-				end
+		
+		-- Make our clone
+		local m = makeParadoxClone(self, self, 2)
+		m.energy.value = 1000
+		m.generic_damage_penalty = m.generic_damage_penalty or 0 + t.getDamagePenalty(self, t)
+		doWardenWeaponSwap(m, t, nil, "blade")
+		m.on_act = function(self)
+			if not self.blended_target.dead then
+				self:forceUseTalent(self.T_ATTACK, {ignore_cd=true, ignore_energy=true, force_target=self.blended_target, ignore_ressources=true, silent=true})
 			end
-			for i, t in ipairs(tids) do
-				if t.mode == "sustained" and m:isTalentActive(t.id) then m:forceUseTalent(t.id, {ignore_energy=true, silent=true}) end
-				m.talents[t.id] = nil
+			self:useEnergy()
+			game:onTickEnd(function()self:die()end)
+			game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
+		end
+		
+		-- Check Focus first
+		local wf = checkWardenFocus(self)
+		if wf and not wf.dead then
+			local tx, ty = util.findFreeGrid(wf.x, wf.y, 1, true, {[Map.ACTOR]=true})
+			if tx and ty then
+				game.zone:addEntity(game.level, m, "actor", tx, ty)
+				m.blended_target = wf
 			end
-
-			m.ai_state = { talent_in=2, ally_compassion=10 }
-			m.generic_damage_penalty = t.getDamagePenalty(self, t)
-			m.remove_from_party_on_death = true
-
-			game.zone:addEntity(game.level, m, "actor", tx, ty)
-
-			m:setTarget(target or nil)
-
-			if game.party:hasMember(self) then
-				game.party:addMember(m, {
-					control="no",
-					type="temporal-clone",
-					title="Blade Warden",
-					orders = {target=true},
-				})
+		end
+		if not m.blended_target then
+			local tgts= t.findTarget(self, t)
+			local attempts = 10
+			while #tgts > 0 and attempts > 0 do
+				local a, id = rng.tableRemove(tgts)
+				-- look for space
+				local tx, ty = util.findFreeGrid(a.x, a.y, 1, true, {[Map.ACTOR]=true})
+				if tx and ty and not a.dead then			
+					game.zone:addEntity(game.level, m, "actor", tx, ty)
+					m.blended_target = a
+					break
+				else
+					attempts = attempts - 1
+				end
 			end
-
-			-- Swap to our blade if needed
-			doWardenWeaponSwap(m, t, 0, "blade")
-			blade_warden = true
+		end
+	end,
+	doBowWarden = function(self, t, target)
+		-- Sanity check
+		game.logPlayer(self, "You are unable to move!")
+		if not self.turn_procs.blade_warden then
+			self.turn_procs.blade_warden = true
 		else
-			game.logPlayer(self, "Not enough space to summon blade warden!")
+			return
 		end
-
-		-- First find a position
-		local bow_warden = false
-		local poss = {}
-		local range = 6
-		for i = x - range, x + range do
-			for j = y - range, y + range do
-				if game.level.map:isBound(i, j) and
-					core.fov.distance(x, y, i, j) <= range and -- make sure they're within arrow range
-					core.fov.distance(i, j, self.x, self.y) <= range/2 and -- try to place them close to the caster so enemies dodge less
-					self:canMove(i, j) and self:hasLOS(i, j) then -- try to keep them in LOS
-					-- Make sure our clone can shoot our target, if we have one
-					if target and target:hasLOS(i, j) then
-						poss[#poss+1] = {i,j}
-					elseif not target then
-						poss[#poss+1] = {i,j}
-					end
+	
+		-- Make our clone
+		local m = makeParadoxClone(self, self, 2)
+		m.energy.value = 1000
+		m.generic_damage_penalty = m.generic_damage_penalty or 0 + t.getDamagePenalty(self, t)
+		m:attr("archery_pass_friendly", 1)
+		doWardenWeaponSwap(m, t, nil, "bow")
+		m.on_act = function(self)
+			if not self.blended_target.dead then
+				local targets = self:archeryAcquireTargets(nil, {one_shot=true, x=self.blended_target.x, y=self.blended_target.y, no_energy = true})
+				if targets then
+					self:forceUseTalent(self.T_SHOOT, {ignore_cd=true, ignore_energy=true, force_target=self.blended_target, ignore_ressources=true, silent=true})
 				end
 			end
+			self:useEnergy()
+			game:onTickEnd(function()self:die()end)
+			game.level.map:particleEmitter(self.x, self.y, 1, "temporal_teleport")
 		end
-		-- Create our archer clone
-		if #poss > 0 then
-			local pos = poss[rng.range(1, #poss)]
-			tx, ty = pos[1], pos[2]
-			game.level.map:particleEmitter(tx, ty, 1, "temporal_teleport")
-
-			-- clone our caster
-			local m = makeParadoxClone(self, self, t.getDuration(self, t))
-
-			-- remove some talents; note most of this is handled by makeParadoxClone, but we want to be more extensive
-			local tids = {}
-			for tid, _ in pairs(m.talents) do
-				local t = m:getTalentFromId(tid)
-				local tt = self:getTalentFromId(tid)
-				if not tt.type[1]:find("^chronomancy/bow") and not tt.type[1]:find("^chronomancy/threaded") and not tt.type[1]:find("^chronomancy/guardian") and not t.innate then
-					tids[#tids+1] = t
+		
+		-- Find a good location for our shot
+		local function find_space(self, target, clone)
+			local poss = {}
+			local range = util.getval(archery_range, clone, t)
+			local x, y = target.x, target.y
+			for i = x - range, x + range do
+				for j = y - range, y + range do
+					if game.level.map:isBound(i, j) and
+						core.fov.distance(x, y, i, j) <= range and -- make sure they're within arrow range
+						core.fov.distance(i, j, self.x, self.y) <= range/2 and -- try to place them close to the caster so enemies dodge less
+						self:canMove(i, j) and target:hasLOS(i, j) then
+						poss[#poss+1] = {i,j}
+					end
 				end
 			end
-			for i, t in ipairs(tids) do
-				if t.mode == "sustained" and m:isTalentActive(t.id) then m:forceUseTalent(t.id, {ignore_energy=true, silent=true}) end
-				m.talents[t.id] = nil
-			end
-
-			m.ai_state = { talent_in=2, ally_compassion=10 }
-			m.generic_damage_penalty = t.getDamagePenalty(self, t)
-			m:attr("archery_pass_friendly", 1)
-			m.remove_from_party_on_death = true
-
-			game.zone:addEntity(game.level, m, "actor", tx, ty)
-
-			m:setTarget(target or nil)
-
-			if game.party:hasMember(self) then
-				game.party:addMember(m, {
-					control="no",
-					type="temporal-clone",
-					title="Bow Warden",
-					orders = {target=true},
-				})
+			if #poss == 0 then return end
+			local pos = poss[rng.range(1, #poss)]
+			x, y = pos[1], pos[2]
+			return x, y
+		end
+		
+		-- Check Focus first
+		local wf = checkWardenFocus(self)
+		if wf and not wf.dead then
+			local tx, ty = find_space(self, target, m)
+			if tx and ty then
+				game.zone:addEntity(game.level, m, "actor", tx, ty)
+				m.blended_target = wf
 			end
-
-			-- Swap to our bow if needed
-			doWardenWeaponSwap(m, t, 0, "bow")
-			bow_warden = true
 		else
-			game.logPlayer(self, "Not enough space to summon bow warden!")
-		end
-
-		game:playSoundNear(self, "talents/teleport")
-
-		if not blade_warden and not bow_warden then  -- If neither summons then don't punish the player
-			game.logPlayer(self, "Not enough space to summon!")
-			return
+			local tgts = t.findTarget(self, t)
+			if #tgts > 0 then
+				local a, id = rng.tableRemove(tgts)
+				local tx, ty = find_space(self, target, m)
+				game.zone:addEntity(game.level, m, "actor", tx, ty)
+				m.blended_target = a
+			end
 		end
-
-		return true
+	end,
+	findTarget = function(self, t)
+		local tgts = {}
+		local grids = core.fov.circle_grids(self.x, self.y, 10, true)
+		for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do
+			local target_type = Map.ACTOR
+			local a = game.level.map(x, y, Map.ACTOR)
+			if a and self:reactionToward(a) < 0 and self:hasLOS(a.x, a.y) then
+				tgts[#tgts+1] = a
+			end
+		end end
+		
+		return tgts
 	end,
 	info = function(self, t)
-		local duration = t.getDuration(self, t)
 		local damage_penalty = t.getDamagePenalty(self, t)
-		return ([[Summons a blade warden and a bow warden from an alternate timeline for %d turns.  The wardens are out of phase with this reality and deal %d%% less damage but the bow warden's arrows will pass through friendly targets.
-		Each warden knows all Threaded Combat, Temporal Guardian, and Blade Threading or Bow Threading spells you know.
-		The damage penalty will be lessened by your Spellpower.]]):format(duration, damage_penalty)
-	end,
+		return ([[When you hit with a blade-threading or a bow-threading talent a warden may appear (depending on available space) from another timeline and shoot or attack a random enemy.
+		The wardens are out of phase with this reality and deal %d%% less damage but the bow warden's arrows will pass through friendly targets.
+		Each of these effects can only occur once per turn and the wardens return to their own timeline after attacking.]])
+		:format(damage_penalty)
+	end
 }
diff --git a/game/modules/tome/data/talents/chronomancy/timeline-threading.lua b/game/modules/tome/data/talents/chronomancy/timeline-threading.lua
index 225f08079dbabf97236874bbf7a06d6c6c31d9fc..cd24c1775c9041d1e25cced32ec6a625837613aa 100644
--- a/game/modules/tome/data/talents/chronomancy/timeline-threading.lua
+++ b/game/modules/tome/data/talents/chronomancy/timeline-threading.lua
@@ -22,7 +22,7 @@
 newTalent{
 	name = "Rethread",
 	type = {"chronomancy/timeline-threading", 1},
-	require = chrono_req1,
+	require = chrono_req_high1,
 	points = 5,
 	cooldown = 4,
 	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
@@ -35,7 +35,7 @@ newTalent{
 		return {type="bolt", range=self:getTalentRange(t), talent=t}
 	end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 230, getParadoxSpellpower(self, t)) end,
-	getTargetCount = function(self, t) return math.floor(self:combatTalentScale(t, 2, 6, "log")) end,
+	getTargetCount = function(self, t) return 3 end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local fx, fy = self:getTarget(tg)
@@ -79,7 +79,6 @@ newTalent{
 			local tgr = {type="beam", range=self:getTalentRange(t), selffire=false, talent=t, x=sx, y=sy}
 			self:project(tgr, actor.x, actor.y, function(px, py)
 				DamageType:get(DamageType.TEMPORAL).projector(self, px, py, DamageType.TEMPORAL, damage)
-				damage = damage * 0.67
 
 				-- Get our braid targets
 				local target = game.level.map(px, py, Map.ACTOR)
@@ -109,7 +108,6 @@ newTalent{
 		local targets = t.getTargetCount(self, t)
 		return ([[Rethread the timeline, dealing %0.2f temporal damage to the target before moving on to a second target.
 		Rethread can hit up to %d targets up to 10 grids apart, and will never hit the same one twice; nor will it hit the caster.
-		Each time it jumps target the damage is reduced by 33%%.
 		The damage will increase with your Spellpower.]]):
 		format(damDesc(self, DamageType.TEMPORAL, damage), targets)
 	end,
@@ -118,7 +116,7 @@ newTalent{
 newTalent{
 	name = "Temporal Fugue",
 	type = {"chronomancy/timeline-threading", 2},
-	require = chrono_req2,
+	require = chrono_req_high2,
 	points = 5,
 	cooldown = 24,
 	paradox = function(self, t) return getParadoxCost(self, t, 20) end,
@@ -198,7 +196,7 @@ newTalent{
 newTalent{
 	name = "Braid Lifelines",
 	type = {"chronomancy/timeline-threading", 3},
-	require = chrono_req3,
+	require = chrono_req_high3,
 	mode = "passive",
 	points = 5,
 	getBraid = function(self, t) return self:combatTalentSpellDamage(t, 25, 40, getParadoxSpellpower(self, t)) end,
@@ -215,7 +213,7 @@ newTalent{
 newTalent{
 	name = "Cease to Exist",
 	type = {"chronomancy/timeline-threading", 4},
-	require = chrono_req4,
+	require = chrono_req_high4,
 	points = 5,
 	cooldown = 24,
 	paradox = function (self, t) return getParadoxCost(self, t, 25) end,
@@ -223,11 +221,8 @@ newTalent{
 	tactical = { ATTACK = 2 },
 	requires_target = true,
 	direct_hit = true,
-	no_npc_use = true,  -- so rares don't learn useless talents
-	allow_temporal_clones = true,  -- let clones copy it anyway so they can benefit from the effects
-	on_pre_use = function(self, t, silent) if self ~= game.player then return false end return true end,  -- but don't let them cast it
-	getDuration = function(self, t) return math.floor(self:combatTalentScale(self:getTalentLevel(t), 5, 9)) end,
-	getPower = function(self, t) return paradoxTalentScale(self, t, 20, 50, 100) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9)) end,
+	getPower = function(self, t) return self:combatTalentScale(t, 20, 50, 100) end,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), talent=t}
 	end,
@@ -292,7 +287,8 @@ newTalent{
 		
 		-- Set our effect
 		target:setEffect(target.EFF_CEASE_TO_EXIST, t.getDuration(self,t), {src=self, power=t.getPower(self,t)})
-				
+		game:playSoundNear(self, "talents/arcane")
+		
 		return true
 	end,
 	info = function(self, t)
@@ -311,13 +307,13 @@ newTalent{
 --[=[newTalent{
 	name = "Temporal Fugue",
 	type = {"chronomancy/timeline-threading", 2},
-	require = chrono_req2,
+	require = chrono_req_high2,
 	points = 5,
 	cooldown = 12,
 	paradox = function (self, t) return getParadoxCost(self, t, 15) end,
 	tactical = { DISABLE = 3 },
 	getDuration = function(self, t) return getExtensionModifier(self, t, math.floor(self:combatTalentScale(t, 4, 8))) end,
-	getDamagePenalty = function(self, t) return 80 - paradoxTalentScale(self, t, 0, 20, 40) end,
+	getDamagePenalty = function(self, t) return 80 - self:combatTalentLimit(t, 0, 20, 40)end,
 	getClones = function(self, t) return 3 end,
 	on_pre_use = function(self, t, silent) if self ~= game.player and self.fugue_clones then return false end return true end,
 	action = function(self, t)
diff --git a/game/modules/tome/data/talents/chronomancy/timetravel.lua b/game/modules/tome/data/talents/chronomancy/timetravel.lua
index f44f0592c6f08e7c01505b988c4d5213bc796a8d..2334c97cb3460cb9d2cf3559165f56b798589a0a 100644
--- a/game/modules/tome/data/talents/chronomancy/timetravel.lua
+++ b/game/modules/tome/data/talents/chronomancy/timetravel.lua
@@ -34,6 +34,7 @@ newTalent{
 	direct_hit = true,
 	requires_target = true,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 15, 150, getParadoxSpellpower(self, t)) end,
+	getCooldown = function(self, t) return self:getTalentLevel(t) >= 5 and 2 or 1 end,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), friendlyfire=false, talent=t}
 	end,
@@ -43,6 +44,7 @@ newTalent{
 		if not x or not y then return nil end
 		
 		local dam = self:spellCrit(t.getDamage(self, t))
+		local cdr = t.getCooldown(self, t)
 		
 		-- Hit our initial target; quality of life hack
 		self:project(tg, x, y, function(px, py)
@@ -52,7 +54,7 @@ newTalent{
 			for tid, cd in pairs(self.talents_cd) do
 				local tt = self:getTalentFromId(tid)
 				if tt.type[1]:find("^chronomancy/") and not tt.fixed_cooldown then
-					self:alterTalentCoolingdown(tt, - 1)
+					self:alterTalentCoolingdown(tt, - cdr)
 				end
 			end
 			DamageType:get(DamageType.TEMPORAL).projector(self, x, y, DamageType.TEMPORAL, dam)
@@ -62,8 +64,8 @@ newTalent{
 		self:project(tg, x, y, function(x, y)
 			local proj = require("mod.class.Projectile"):makeHoming(
 				self,
-				{particle="arrow", particle_args={tile="particles_images/temporal_bolt", proj_x=self.x, proj_y=self.y, src_x=x, src_y=y},  trail="trail_paradox"},
-				{speed=3, name="Temporal Bolt", dam=dam, apply=getParadoxSpellpower(self, t), start_x=x, start_y=y},
+				{particle="arrow", particle_args={tile="particles_images/temporal_bolt", proj_x=self.x, proj_y=self.y, src_x=x, src_y=y}, trail="trail_paradox"},
+				{speed=3, name="Temporal Bolt", dam=dam, cdr=cdr, start_x=x, start_y=y},
 				self, self:getTalentRange(t),
 				function(self, src)
 					local talent = src:getTalentFromId 'T_TEMPORAL_BOLT'
@@ -78,7 +80,8 @@ newTalent{
 						for tid, cd in pairs(src.talents_cd) do
 							local tt = src:getTalentFromId(tid)
 							if tt.type[1]:find("^chronomancy/") and not tt.fixed_cooldown then
-								src:alterTalentCoolingdown(tt, - 1)
+								src:alterTalentCoolingdown(tt, - self.def.cdr)
+								break
 							end
 						end
 					end
@@ -89,61 +92,112 @@ newTalent{
 			game.zone:addEntity(game.level, proj, "projectile", x, y)
 		end)
 			
-		game:playSoundNear({x=x, y=y}, "talents/distortion")
+		game:playSoundNear({x=x, y=y}, "talents/spell_generic2")
 
 		return true
 	end,
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		return ([[Pull a bolt of temporal energy back through time.  The bolt will home in on your location, dealing %0.2f temporal damage to enemies, and reducing the cooldown of one chronomancy talent on cooldown by one turn per enemy hit.
-		The bolt gains 5%% damage each time it moves and the damage will scale with your Spellpower.]]):
+		The bolt gains 5%% damage each time it moves and the damage will scale with your Spellpower.
+		At talent level five cooldowns are reduced by two.]]):
 		format(damDesc(self, DamageType.TEMPORAL, damage))
 	end,
 }
 
 newTalent{
-	name = "Echoes From The Past",
-	type = {"chronomancy/timetravel", 2},
+	name = "Time Skip",
+	type = {"chronomancy/timetravel",2},
 	require = chrono_req2,
 	points = 5,
-	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
-	cooldown = 10,
-	tactical = { ATTACKAREA = {TEMPORAL = 2} },
-	range = 0,
-	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2, 6)) end,
-	target = function(self, t)
-		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
-	end,
+	cooldown = 6,
+	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
+	tactical = { ATTACK = {TEMPORAL = 1}, DISABLE = 2 },
+	range = 10,
 	direct_hit = true,
 	requires_target = true,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 18, 160, getParadoxSpellpower(self, t)) end,
-	getPercent = function(self, t) return paradoxTalentScale(self, t, 20, 40, 60)/100 end,
+	target = function(self, t)
+		return {type="hit", range=self:getTalentRange(t), talent=t}
+	end,
+	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 25, 250, getParadoxSpellpower(self, t)) end,
+	getDuration = function(self, t) return getExtensionModifier(self, t, 2 + math.ceil(self:combatTalentScale(t, 0.3, 2.3))) end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		local _ _, x, y = self:canProject(tg, x, y)
+		local target = game.level.map(x, y, Map.ACTOR)
+		if not target then return end
+
+		if target:attr("timetravel_immune") then
+			game.logSeen(target, "%s is immune!", target.name:capitalize())
+			return true
+		end
+
+		-- Project our damage
+		self:project(tg, x, y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t)))
 		
-		local damage = self:spellCrit(t.getDamage(self, t))
-		self:project(tg, self.x, self.y, function(px, py)
-			DamageType:get(DamageType.TEMPORAL).projector(self, px, py, DamageType.TEMPORAL, damage)
-			
-			-- Echo
-			local target = game.level.map(px, py, Map.ACTOR)
-			if not target then return end
-			local percent = t.getPercent(self, t)/target.rank
-			local dam = (target.max_life - target.life) * percent
-			DamageType:get(DamageType.TEMPORAL).projector(self, px, py, DamageType.TEMPORAL, dam)
-		end)
+		game.level.map:particleEmitter(x, y, 1, "temporal_thrust")
+		game:playSoundNear(self, "talents/arcane")
 		
-		game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_temporal", {radius=tg.radius})
-		game:playSoundNear(self, "talents/teleport")
+		-- If they're dead don't remove them from time
+		if target.dead or target.player then return true end
+		
+		-- Check hit
+		local power = getParadoxSpellpower(self, t)
+		local hit = self:checkHit(power, target:combatSpellResist() + (target:attr("continuum_destabilization") or 0))
+		if not hit then game.logSeen(target, "%s resists!", target.name:capitalize()) return true end
+		
+		-- Apply spellshock and destabilization
+		target:crossTierEffect(target.EFF_SPELLSHOCKED, getParadoxSpellpower(self, t))
+		target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=getParadoxSpellpower(self, t, 0.3)})
+		
+		-- Placeholder for the actor
+		local oe = game.level.map(target.x, target.y, engine.Map.TERRAIN)
+		if not oe or oe:attr("temporary") then return true end
+		local e = mod.class.Object.new{
+			old_feat = oe, type = oe.type, subtype = oe.subtype,
+			name = "temporal instability", image = oe.image, add_mos = {{image="object/temporal_instability.png"}},
+			display = '&', color=colors.LIGHT_BLUE,
+			temporary = t.getDuration(self, t),
+			canAct = false,
+			target = target,
+			act = function(self)
+				self:useEnergy()
+				self.temporary = self.temporary - 1
+				-- return the rifted actor
+				if self.temporary <= 0 then
+					game.level.map(self.target.x, self.target.y, engine.Map.TERRAIN, self.old_feat)
+					game.nicer_tiles:updateAround(game.level, self.target.x, self.target.y)
+					game.level:removeEntity(self)
+					local mx, my = util.findFreeGrid(self.target.x, self.target.y, 20, true, {[engine.Map.ACTOR]=true})
+					local old_levelup = self.target.forceLevelup
+					local old_check = self.target.check
+					self.target.forceLevelup = function() end
+					self.target.check = function() end
+					game.zone:addEntity(game.level, self.target, "actor", mx, my)
+					self.target.forceLevelup = old_levelup
+					self.target.check = old_check
+				end
+			end,
+			summoner_gain_exp = true, summoner = self,
+		}
+		
+		-- Replace the target with the instability and update the map
+		game.logSeen(target, "%s has moved forward in time!", target.name:capitalize())
+		game.level:removeEntity(target, true)
+		e.tooltip = mod.class.Grid.tooltip
+		game.level:addEntity(e)
+		game.level.map(x, y, Map.TERRAIN, e)
+		game.nicer_tiles:updateAround(game.level, x, y)
+		game.level.map:updateMap(x, y)
 		return true
 	end,
 	info = function(self, t)
-		local percent = t.getPercent(self, t) * 100
-		local radius = self:getTalentRadius(t)
 		local damage = t.getDamage(self, t)
-		return ([[Creates a temporal echo in a radius of %d around you.  Affected targets will take %0.2f temporal damage, as well as up to %d%% of the difference between their current life and max life as additional temporal damage.
-		The additional damage will be divided by the target's rank and the damage scales with your Spellpower.]]):
-		format(radius, damDesc(self, DamageType.TEMPORAL, damage), percent)
+		local duration = t.getDuration(self, t)
+		return ([[Inflicts %0.2f temporal damage.  If your target survives, it may be removed from time for %d turns.
+		The damage will scale with your Spellpower.]]):format(damDesc(self, DamageType.TEMPORAL, damage), duration)
 	end,
 }
 
@@ -228,96 +282,47 @@ newTalent{
 }
 
 newTalent{
-	name = "Time Skip",
-	type = {"chronomancy/timetravel",4},
+	name = "Echoes From The Past",
+	type = {"chronomancy/timetravel", 4},
 	require = chrono_req4,
 	points = 5,
-	cooldown = 4,
-	paradox = function (self, t) return getParadoxCost(self, t, 10) end,
-	tactical = { ATTACK = {TEMPORAL = 1}, DISABLE = 2 },
-	range = 10,
-	direct_hit = true,
-	requires_target = true,
+	paradox = function (self, t) return getParadoxCost(self, t, 20) end,
+	cooldown = 12,
+	tactical = { ATTACKAREA = {TEMPORAL = 2} },
+	range = 0,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	target = function(self, t)
-		return {type="hit", range=self:getTalentRange(t), talent=t}
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
 	end,
-	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 25, 250, getParadoxSpellpower(self, t)) end,
-	getDuration = function(self, t) return getExtensionModifier(self, t, 2 + math.ceil(self:combatTalentScale(self:getTalentLevel(t), 0.3, 2.3))) end,
+	direct_hit = true,
+	requires_target = true,
+	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 220, getParadoxSpellpower(self, t)) end,
+	getPercent = function(self, t) return self:combatTalentLimit(t, 60, 20, 40)/100 end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		local x, y = self:getTarget(tg)
-		if not x or not y then return nil end
-		local _ _, x, y = self:canProject(tg, x, y)
-		local target = game.level.map(x, y, Map.ACTOR)
-		if not target then return end
-
-		if target:attr("timetravel_immune") then
-			game.logSeen(target, "%s is immune!", target.name:capitalize())
-			return true
-		end
-
-		-- Project our damage
-		self:project(tg, x, y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t)))
 		
-		game.level.map:particleEmitter(x, y, 1, "temporal_thrust")
-		game:playSoundNear(self, "talents/arcane")
-		
-		-- If they're dead don't remove them from time
-		if target.dead or target.player then return true end
-		
-		-- Check hit
-		local power = getParadoxSpellpower(self, t)
-		local hit = self:checkHit(power, target:combatSpellResist() + (target:attr("continuum_destabilization") or 0))
-		if not hit then game.logSeen(target, "%s resists!", target.name:capitalize()) return true end
-		
-		-- Apply spellshock and destabilization
-		target:crossTierEffect(target.EFF_SPELLSHOCKED, getParadoxSpellpower(self, t))
-		target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=getParadoxSpellpower(self, t, 0.3)})
-		
-		-- Placeholder for the actor
-		local oe = game.level.map(target.x, target.y, engine.Map.TERRAIN)
-		if not oe or oe:attr("temporary") then return true end
-		local e = mod.class.Object.new{
-			old_feat = oe, type = oe.type, subtype = oe.subtype,
-			name = "temporal instability", image = oe.image, add_mos = {{image="object/temporal_instability.png"}},
-			display = '&', color=colors.LIGHT_BLUE,
-			temporary = t.getDuration(self, t),
-			canAct = false,
-			target = target,
-			act = function(self)
-				self:useEnergy()
-				self.temporary = self.temporary - 1
-				-- return the rifted actor
-				if self.temporary <= 0 then
-					game.level.map(self.target.x, self.target.y, engine.Map.TERRAIN, self.old_feat)
-					game.nicer_tiles:updateAround(game.level, self.target.x, self.target.y)
-					game.level:removeEntity(self)
-					local mx, my = util.findFreeGrid(self.target.x, self.target.y, 20, true, {[engine.Map.ACTOR]=true})
-					local old_levelup = self.target.forceLevelup
-					local old_check = self.target.check
-					self.target.forceLevelup = function() end
-					self.target.check = function() end
-					game.zone:addEntity(game.level, self.target, "actor", mx, my)
-					self.target.forceLevelup = old_levelup
-					self.target.check = old_check
-				end
-			end,
-			summoner_gain_exp = true, summoner = self,
-		}
+		local damage = self:spellCrit(t.getDamage(self, t))
+		self:project(tg, self.x, self.y, function(px, py)
+			DamageType:get(DamageType.TEMPORAL).projector(self, px, py, DamageType.TEMPORAL, damage)
+			
+			-- Echo
+			local target = game.level.map(px, py, Map.ACTOR)
+			if not target then return end
+			local percent = t.getPercent(self, t)/target.rank
+			local dam = (target.max_life - target.life) * percent
+			DamageType:get(DamageType.TEMPORAL).projector(self, px, py, DamageType.TEMPORAL, dam)
+		end)
 		
-		-- Replace the target with the instability and update the map
-		game.logSeen(target, "%s has moved forward in time!", target.name:capitalize())
-		game.level:removeEntity(target, true)
-		game.level:addEntity(e)
-		game.level.map(x, y, Map.TERRAIN, e)
-		game.nicer_tiles:updateAround(game.level, x, y)
-		game.level.map:updateMap(x, y)
+		game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_temporal", {radius=tg.radius})
+		game:playSoundNear(self, "talents/warp")
 		return true
 	end,
 	info = function(self, t)
+		local percent = t.getPercent(self, t) * 100
+		local radius = self:getTalentRadius(t)
 		local damage = t.getDamage(self, t)
-		local duration = t.getDuration(self, t)
-		return ([[Inflicts %0.2f temporal damage.  If your target survives, it may be removed from time for %d turns.
-		The damage will scale with your Spellpower.]]):format(damDesc(self, DamageType.TEMPORAL, damage), duration)
+		return ([[Creates a temporal echo in a radius of %d around you.  Affected targets will take %0.2f temporal damage, as well as up to %d%% of the difference between their current life and max life as additional temporal damage.
+		The additional damage will be divided by the target's rank and the damage scales with your Spellpower.]]):
+		format(radius, damDesc(self, DamageType.TEMPORAL, damage), percent)
 	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/misc/horrors.lua b/game/modules/tome/data/talents/misc/horrors.lua
index 2819823b707c7d96de3fa3ae33280513562c1998..174cf75dc1550dcf5ee418b77cd990c22bc40081 100644
--- a/game/modules/tome/data/talents/misc/horrors.lua
+++ b/game/modules/tome/data/talents/misc/horrors.lua
@@ -581,7 +581,7 @@ newTalent{
 	getDamage = function(self, t) return self:combatTalentMindDamage(t, 5, 70) end,
 	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3, 7)) end,
 	action = function(self, t)
-		local tg = self:getTarget(t)
+		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
 		local target = game.level.map(x, y, engine.Map.ACTOR)
 		if not x or not y or not target then return nil end
diff --git a/game/modules/tome/data/talents/misc/misc.lua b/game/modules/tome/data/talents/misc/misc.lua
index 1e947286b050059bbd251aa6f66cd74a387b00c3..c7311f67fac30252ceb3ed3eb318236784035725 100644
--- a/game/modules/tome/data/talents/misc/misc.lua
+++ b/game/modules/tome/data/talents/misc/misc.lua
@@ -52,13 +52,15 @@ newTalent{
 	speed = 'weapon',
 	is_melee = true,
 	action = function(self, t)
+		local swap = self:attr("warden_swap") and doWardenWeaponSwap(self, t, nil, "blade")
+	
 		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
 		if not x then return end
 		local _ _, x, y = self:canProject(tg, x, y)
 		if not x then return end
 		local target = game.level.map(x, y, engine.Map.ACTOR)
-		if not target then return end
+		if not target then if swap then doWardenWeaponSwap(self, t, nil, "bow") end return end
 
 		local did_alternate = false
 		for _, alt_t in ipairs(t.alternate_attacks) do
diff --git a/game/modules/tome/data/talents/misc/npcs.lua b/game/modules/tome/data/talents/misc/npcs.lua
index ff1350a6d7a6dd2e06107c6ce83e9b9e911e78f2..990a5a9d412ec05b0e044bf7e36c3a52e9a70506 100644
--- a/game/modules/tome/data/talents/misc/npcs.lua
+++ b/game/modules/tome/data/talents/misc/npcs.lua
@@ -1574,7 +1574,7 @@ newTalent{
 	target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 220, getParadoxSpellpower(self, t)) end,
 	action = function(self, t)
-		local tg = self:getTalentTarget()
+		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
 		if not x or not y then return nil end
 		self:project(tg, x, y, DamageType.WASTING, self:spellCrit(t.getDamage(self, t)))
diff --git a/game/modules/tome/data/talents/psionic/augmented-striking.lua b/game/modules/tome/data/talents/psionic/augmented-striking.lua
index 637599664e797fdcf4897907c7cc45b2f2760134..c4c80078f76b25b5a17b0e4388c752d2302ca751 100644
--- a/game/modules/tome/data/talents/psionic/augmented-striking.lua
+++ b/game/modules/tome/data/talents/psionic/augmented-striking.lua
@@ -128,7 +128,7 @@ newTalent{
 			game.logPlayer(self, "You cannot do that without a weapon in your hands.")
 			return nil
 		end
-		local tg = self:getTarget(t)
+		local tg = self:getTalentTarget(t)
 		local x, y, target = self:getTarget(tg)
 		if not target or not self:canProject(tg, x, y) then return nil end
 		local dam = self:mindCrit(t.getDam(self, t))
diff --git a/game/modules/tome/data/talents/psionic/thought-forms.lua b/game/modules/tome/data/talents/psionic/thought-forms.lua
index 3b4e5efe388adcea4dc3739d4b0343f9062fb84d..c3dfdc438f01c02d28d7241148daf5d86f46f2c4 100644
--- a/game/modules/tome/data/talents/psionic/thought-forms.lua
+++ b/game/modules/tome/data/talents/psionic/thought-forms.lua
@@ -43,7 +43,7 @@ local function setupAct(self)
 	self.on_act = function(self)
 		local tid = self.summoning_tid
 		if not game.level:hasEntity(self.summoner) or self.summoner.dead or not self.summoner:isTalentActive(tid) then
-			self:die(self)
+			game:onTickEnd(function()self:die(self)end)
 		end
 		if game.level:hasEntity(self.summoner) and core.fov.distance(self.x, self.y, self.summoner.x, self.summoner.y) > 10 then
 			local Map = require "engine.Map"
diff --git a/game/modules/tome/data/talents/techniques/archery.lua b/game/modules/tome/data/talents/techniques/archery.lua
index 090ac2f2ddb2421bcb7ebe1dc0bbfd5a2f72e48d..f469f49d18bab742bec580e95a59f48d7ef98c66 100644
--- a/game/modules/tome/data/talents/techniques/archery.lua
+++ b/game/modules/tome/data/talents/techniques/archery.lua
@@ -37,7 +37,7 @@ newTalent{
 	message = "@Source@ shoots!",
 	requires_target = true,
 	tactical = { ATTACK = { weapon = 1 } },
-	on_pre_use = function(self, t, silent) if not self:hasArcheryWeapon() then if not silent then game.logPlayer(self, "You require a bow or sling for this talent.") end return false end return true end,
+	on_pre_use = function(self, t, silent) if not (self:attr("warden_swap") and doWardenPreUse(self, "bow")) and not self:hasArcheryWeapon() then if not silent then game.logPlayer(self, "You require a bow or sling for this talent.") end return false end return true end,
 	no_unlearn_last = true,
 	use_psi_archery = function(self, t)
 		local inven = self:getInven("PSIONIC_FOCUS")
@@ -50,14 +50,16 @@ newTalent{
 		end
 	end,
 	action = function(self, t)
+		local swap = self:attr("warden_swap") and doWardenWeaponSwap(self, t, nil, "bow")
+	
 		-- Most of the time use the normal shoot.
 		if not self:hasArcheryWeapon("sling") or not self:isTalentActive("T_SKIRMISHER_BOMBARDMENT") then
 			local targets = self:archeryAcquireTargets(nil, {one_shot=true})
-			if not targets then return end
+			if not targets then if swap then doWardenWeaponSwap(self, t, nil, "blade") end return end
 			self:archeryShoot(targets, t, nil, {use_psi_archery = t.use_psi_archery(self, t)})
 			return true
 		end
-
+		
 		local weapon, ammo, offweapon = self:hasArcheryWeapon()
 		if not weapon then return nil end
 		local infinite = ammo.infinite or self:attr("infinite_ammo")
diff --git a/game/modules/tome/data/texts/unlock-chronomancer_paradox_mage.lua b/game/modules/tome/data/texts/unlock-chronomancer_paradox_mage.lua
index fc319e7f9e208df324ff2acd1458f8b422d8c9c4..4e031ea94834a71d2e6e7b7a18de2bd499cfc982 100644
--- a/game/modules/tome/data/texts/unlock-chronomancer_paradox_mage.lua
+++ b/game/modules/tome/data/texts/unlock-chronomancer_paradox_mage.lua
@@ -22,6 +22,7 @@ return "New Class: #LIGHT_GREEN#Paradox Mage (Chronomancer)",
 Some seek to weave this fabric, to bend it and shape it to their own will.  Only the truly dedicated or the truly mad manage to unlock the secrets of time and space.
 
 You have learned such secrets and can now create new characters with the #LIGHT_GREEN#Paradox Mage class#WHITE#.
+Additionally you may now create new Temporal Warden characters that can learn the #LIGHT_GREEN#Timeline Threading talents#WHITE#.
 
 Paradox Mages are non-traditional spell casters who use chronomancy to reshape the universe.
 Class features:#YELLOW#
diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua
index f2764560d27e0204c66fde7f8deac4fc2d64b095..a62007d45f0ba0df223f77fab76154f3c240fb9c 100644
--- a/game/modules/tome/data/timed_effects/magical.lua
+++ b/game/modules/tome/data/timed_effects/magical.lua
@@ -1320,7 +1320,7 @@ newEffect{
 newEffect{
 	name = "INVIGORATE", image = "talents/invigorate.png",
 	desc = "Invigorate",
-	long_desc = function(self, eff) return ("The target is regaining %d life per turn and refreshing chronomancy spells at twice the normal rate."):format(eff.power) end,
+	long_desc = function(self, eff) return ("The target is regaining %d life per turn, %d stamina per turn, and refreshing chronomancy spells at twice the normal rate."):format(eff.power, eff.power/2) end,
 	type = "magical",
 	subtype = { temporal=true },
 	status = "beneficial",
@@ -1338,7 +1338,8 @@ newEffect{
 		end
 	end,
 	activate = function(self, eff)
-		eff.tmpid = self:addTemporaryValue("life_regen", eff.power)
+		eff.regenid = self:addTemporaryValue("life_regen", eff.power)
+		eff.stamid = self:addTemporaryValue("stamina_regen", eff.power / 2)
 		if core.shader.active(4) then
 			eff.particle1 = self:addParticles(Particles.new("shader_shield", 1, {toback=true,  size_factor=1.5, y=-0.3, img="healcelestial"}, {type="healing", time_factor=4000, noup=2.0, beamColor1={0xd8/255, 0xff/255, 0x21/255, 1}, beamColor2={0xf7/255, 0xff/255, 0x9e/255, 1}, circleColor={0,0,0,0}, beamsCount=5}))
 			eff.particle2 = self:addParticles(Particles.new("shader_shield", 1, {toback=false, size_factor=1.5, y=-0.3, img="healcelestial"}, {type="healing", time_factor=4000, noup=1.0, beamColor1={0xd8/255, 0xff/255, 0x21/255, 1}, beamColor2={0xf7/255, 0xff/255, 0x9e/255, 1}, circleColor={0,0,0,0}, beamsCount=5}))
@@ -1347,7 +1348,8 @@ newEffect{
 	deactivate = function(self, eff)
 		self:removeParticles(eff.particle1)
 		self:removeParticles(eff.particle2)
-		self:removeTemporaryValue("life_regen", eff.tmpid)
+		self:removeTemporaryValue("life_regen", eff.regenid)
+		self:removeTemporaryValue("stamina_regen", eff.stamid)
 	end,
 }
 
@@ -1526,24 +1528,91 @@ newEffect{
 	end,
 }
 
+newEffect{
+	name = "CELERITY", image = "talents/celerity.png",
+	desc = "Celerity",
+	long_desc = function(self, eff) return ("The target is moving is %d%% faster."):format(eff.speed * 100 * eff.charges) end,
+	type = "magical",
+	display_desc = function(self, eff) return eff.charges.." Celerity" end,
+	charges = function(self, eff) return eff.charges end,
+	subtype = { speed=true, temporal=true },
+	status = "beneficial",
+	parameters = {speed=0.1, charges=1, max_charges=3},
+	on_merge = function(self, old_eff, new_eff)
+		-- remove the old value
+		self:removeTemporaryValue("movement_speed", old_eff.tmpid)
+		
+		-- add a charge
+		old_eff.charges = math.min(old_eff.charges + 1, new_eff.max_charges)
+		
+		-- and apply the current values	
+		old_eff.tmpid = self:addTemporaryValue("movement_speed", old_eff.speed * old_eff.charges)
+		
+		old_eff.dur = new_eff.dur
+		return old_eff
+	end,
+	activate = function(self, eff)
+		eff.tmpid = self:addTemporaryValue("movement_speed", eff.speed * eff.charges)
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("movement_speed", eff.tmpid)
+	end,
+}
+
+newEffect{
+	name = "TIME_DILATION", image = "talents/time_dilation.png",
+	desc = "Time Dilation",
+	long_desc = function(self, eff) return ("Increases attack, spell, and mind speed by %d%%."):format(eff.speed * 100 * eff.charges) end,
+	type = "magical",
+	display_desc = function(self, eff) return eff.charges.." Time Dilation" end,
+	charges = function(self, eff) return eff.charges end,
+	subtype = { speed=true, temporal=true },
+	status = "beneficial",
+	parameters = {speed=0.1, charges=1, max_charges=3},
+	on_merge = function(self, old_eff, new_eff)
+		-- remove the old value
+		self:removeTemporaryValue("combat_physspeed", old_eff.physid)
+		self:removeTemporaryValue("combat_spellspeed", old_eff.spellid)
+		self:removeTemporaryValue("combat_mindspeed", old_eff.mindid)
+		
+		-- add a charge
+		old_eff.charges = math.min(old_eff.charges + 1, new_eff.max_charges)
+		
+		-- and apply the current values	
+		old_eff.physid = self:addTemporaryValue("combat_physspeed", old_eff.speed * old_eff.charges)
+		old_eff.spellid = self:addTemporaryValue("combat_spellspeed", old_eff.speed * old_eff.charges)
+		old_eff.mindid = self:addTemporaryValue("combat_mindspeed", old_eff.speed * old_eff.charges)
+		
+		old_eff.dur = new_eff.dur
+		return old_eff
+	end,
+	activate = function(self, eff)
+		eff.physid = self:addTemporaryValue("combat_physspeed", eff.speed * eff.charges)
+		eff.spellid = self:addTemporaryValue("combat_spellspeed", eff.speed * eff.charges)
+		eff.mindid = self:addTemporaryValue("combat_mindspeed", eff.speed * eff.charges)
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("combat_physspeed", eff.physid)
+		self:removeTemporaryValue("combat_spellspeed", eff.spellid)
+		self:removeTemporaryValue("combat_mindspeed", eff.mindid)
+	end,
+}
+
 newEffect{
 	name = "HASTE", image = "talents/haste.png",
 	desc = "Haste",
-	long_desc = function(self, eff) return ("Increases movement speed by %d%% and attack, spell, and mind speed by %d%%."):format(eff.move * 100, eff.speed * 100) end,
+	long_desc = function(self, eff) return ("Increases global action speed by %d%%."):format(eff.power * 100) end,
 	type = "magical",
-	subtype = { temporal=true },
+	subtype = { temporal=true, speed=true },
 	status = "beneficial",
 	parameters = { move=0.1, speed=0.1 },
 	on_gain = function(self, err) return "#Target# speeds up.", "+Haste" end,
 	on_lose = function(self, err) return "#Target# slows down.", "-Haste" end,
 	activate = function(self, eff)
-		self:effectTemporaryValue(eff, "movement_speed", eff.move)
-		self:effectTemporaryValue(eff, "combat_physspeed", eff.speed)
-		self:effectTemporaryValue(eff, "combat_spellspeed", eff.speed)
-		self:effectTemporaryValue(eff, "combat_mindspeed", eff.speed)
+		eff.tmpid = self:addTemporaryValue("global_speed_add", eff.power)
 	end,
 	deactivate = function(self, eff)
-		self:removeTemporaryValue("global_speed_add", eff.glbid)
+		self:removeTemporaryValue("global_speed_add", eff.tmpid)
 	end,
 }
 
@@ -1638,7 +1707,7 @@ newEffect{
 	status = "beneficial",
 	parameters = { save_bonus=0, spin=0, max_spin=3},
 	on_gain = function(self, err) return "#Target# spins fate.", "+Spin Fate" end,
-	on_lose = function(self, err) return "#Target#'s fate is no longer being spun.", "-Spin Fate" end,
+	on_lose = function(self, err) return "#Target# stops spinning fate.", "-Spin Fate" end,
 	on_merge = function(self, old_eff, new_eff)
 		-- remove the four old values
 		self:removeTemporaryValue("combat_def", old_eff.defid)
@@ -2874,9 +2943,17 @@ newEffect{
 	type = "magical",
 	subtype = { temporal=true, slow=true },
 	status = "detrimental",
-	parameters = { damage=0},
+	parameters = { damage=0, daze=1},
 	on_gain = function(self, err) return "#Target# is anchored.", "+Anchor" end,
 	on_lose = function(self, err) return "#Target# is no longer anchored.", "-Anchor" end,
+	onTeleport = function(self, eff)
+		DamageType:get(DamageType.WARP).projector(eff.src or self, self.x, self.y, DamageType.WARP, eff.damage)
+		game:onTickEnd(function()
+			if self:canBe("stun") then
+				self:setEffect(self.EFF_DAZED, eff.daze, {})
+			end
+		end)
+	end,
 }
 
 newEffect{
@@ -2971,16 +3048,46 @@ newEffect{
 newEffect{
 	name = "WEBS_OF_FATE", image = "talents/webs_of_fate.png",
 	desc = "Webs of Fate",
-	long_desc = function(self, eff) return ("Moving along the webs of fate, increasing stun and pin immunity by %d%%."):format(eff.imm*100) end,
+	long_desc = function(self, eff) return ("Displacing %d%% of all damage on to a random enemy."):format(eff.power*100) end,
 	type = "magical",
-	subtype = { temporal=true, speed=true },
+	subtype = { temporal=true },
 	status = "beneficial",
-	on_gain = function(self, err) return "#Target# moves along the webs of fate.", "+Fate Webs" end,
-	on_lose = function(self, err) return "#Target# is no longer moving along the webs of fate.", "-Fate Webs" end,
-	parameters = { imm=0.1 },
+	on_gain = function(self, err) return nil, "+Webs of Fate" end,
+	on_lose = function(self, err) return nil, "-Webs of Fate" end,
+	parameters = { power=0.1 },
+	callbackOnTakeDamage = function(self, eff, src, x, y, type, dam, tmp)
+		-- Spin Fate?
+		if self.turn_procs and not self.turn_procs.spin_webs then
+			self.turn_procs.spin_webs = true
+			self:callTalent(self.T_SPIN_FATE, "doSpin")
+		end
+	
+		-- Displace Damage?
+		local t = eff.talent
+		if dam > 0 and src ~= self then
+			-- find available targets
+			local tgts = {}
+			local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true)
+			for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do
+				local a = game.level.map(x, y, Map.ACTOR)
+				if a and self:reactionToward(a) < 0 then
+					tgts[#tgts+1] = a
+				end
+			end end
+
+			-- Displace the damage
+			local a = rng.table(tgts)
+			if a then
+				local displace = dam * eff.power
+				DamageType.defaultProjector(self, a.x, a.y, type, displace, {no_reflect=true})
+				dam = dam - displace
+				game:delayedLogDamage(src, self, 0, ("%s(%d webs of fate)#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", displace), false)
+			end
+		end
+		
+		return {dam=dam}
+	end,
 	activate = function(self, eff)
-		self:effectTemporaryValue(eff, "pin_immune", eff.imm)
-		self:effectTemporaryValue(eff, "stun_immune", eff.imm)
 	end,
 	deactivate = function(self, eff)
 	end,
@@ -2994,9 +3101,18 @@ newEffect{
 	subtype = { focus=true },
 	status = "beneficial",
 	parameters = { procs=1 },
-	on_gain = function(self, err) return "#Target# seals fate.", "+Seal Fate" end,
-	on_lose = function(self, err) return "#Target# is no longer sealing fate.", "-Seal Fate" end,
-	doDamage = function(self, eff, target)
+	on_gain = function(self, err) return nil, "+Seal Fate" end,
+	on_lose = function(self, err) return nil, "-Seal Fate" end,
+	callbackOnDealDamage = function(self, eff, dam, target)
+		if dam <=0 then return end
+		
+		-- Spin Fate?
+		if self.turn_procs and not self.turn_procs.spin_seal then
+			self.turn_procs.spin_seal = true
+			self:callTalent(self.T_SPIN_FATE, "doSpin")
+		end
+	
+	
 		if self.turn_procs and target.tmp then
 			if self.turn_procs.seal_fate and self.turn_procs.seal_fate >= eff.procs then return end
 			local chance = 50
@@ -3017,8 +3133,6 @@ newEffect{
 				
 				if #effs > 0 then
 					local p = rng.table(effs)
-					game.logPlayer(self, "%s", p.name)
-					game.logPlayer(self, "%s", p.dur)
 					p.dur = p.dur + 1
 				end
 			
@@ -3105,19 +3219,6 @@ newEffect{
 	end,
 }
 
-newEffect{
-	name = "PHASE_SHIFT", image = "talents/phase_shift.png",
-	desc = "Phase Shift",
-	long_desc = function(self, eff) return ("When hit for more than 10%% of your maximum life you teleport and reappear near where you were, reducuing the damage by 50%%.") end,
-	type = "magical",
-	subtype = { arcane=true },
-	status = "beneficial",
-	parameters = { },
-	activate = function(self, eff)
-		self:effectTemporaryValue(eff, "phase_shift_chrono", 1)
-	end,
-}
-
 newEffect{
 	name = "REGRESSION", image = "talents/temporal_bolt.png",
 	desc = "Regression",
@@ -3138,15 +3239,15 @@ newEffect{
 }
 
 newEffect{
-	name = "TRIM_THREADS", image = "talents/trim_threads.png",
-	desc = "Trim Threads",
-	long_desc = function(self, eff) return ("The target is being cut from the timeline and is taking %0.2f temporal damage per turn."):format(eff.power) end,
+	name = "ATTENUATE", image = "talents/attenuate.png",
+	desc = "Attenuate",
+	long_desc = function(self, eff) return ("The target is being removed from the timeline and is taking %0.2f temporal damage per turn."):format(eff.power, eff.dt_name) end,
 	type = "magical",
 	subtype = { temporal=true },
 	status = "detrimental",
 	parameters = { power=10 },
-	on_gain = function(self, err) return "#Target# is being cut from the timeline!", "+Trim Threads" end,
-	on_lose = function(self, err) return "#Target# is no longer being cut from the timeline.", "-Trim Threads" end,
+	on_gain = function(self, err) return "#Target# is being being removed from the timeline!", "+Attenuate" end,
+	on_lose = function(self, err) return "#Target# survived the attenuation.", "-Attenuate" end,
 	on_merge = function(self, old_eff, new_eff)
 		-- Merge the flames!
 		local olddam = old_eff.power * old_eff.dur
@@ -3277,4 +3378,114 @@ newEffect{
 			end
 		end
 	end,
+}
+
+newEffect{
+	name = "STATIC_HISTORY", image = "talents/static_history.png",
+	desc = "Static History",
+	long_desc = function(self, eff) return ("Chronomancy spells cast by the target cost %d%% less Paradox"):format(eff.power *100) end,
+	type = "magical",
+	subtype = { time=true },
+	status = "beneficial",
+	parameters = { power=0.1 },
+	on_gain = function(self, err) return "Spacetime has stabilized around #Target#.", "+Static History" end,
+	on_lose = function(self, err) return "The fabric of spacetime around #Target# has returned to normal.", "-Static History" end,
+	activate = function(self, eff)
+		self:effectTemporaryValue(eff, "paradox_cost_multiplier", eff.power)
+	end,
+	deactivate = function(self, eff)
+	end,
+}
+
+newEffect{
+	name = "ARROW_ECHOES", image = "talents/arrow_echoes.png",
+	desc = "Arrow Echoes",
+	long_desc = function(self, eff) return ("Each turn will fire an arrow at %s."):format(eff.target.name) end,
+	type = "magical",
+	subtype = { time=true },
+	status = "beneficial",
+	on_gain = function(self, err) return nil, "+Arrow Echoes" end,
+	on_lose = function(self, err) return nil, "-Arrow Echoes" end,
+	parameters = { shots = 1 },
+	on_timeout = function(self, eff)
+		if eff.shots <= 0 or eff.target.dead or not game.level:hasEntity(self) or not game.level:hasEntity(eff.target) or core.fov.distance(self.x, self.y, eff.target.x, eff.target.y) > 10 then
+			self:removeEffect(self.EFF_ARROW_ECHOES)
+		else
+			self:callTalent(self.T_ARROW_ECHOES, "doEcho", eff)
+		end
+	end,
+	activate = function(self, eff)
+	end,
+	deactivate = function(self, eff)
+	end,
+}
+
+newEffect{
+	name = "WARDEN_S_FOCUS", image = "talents/warden_s_focus.png",
+	desc = "Warden's Focus",
+	long_desc = function(self, eff) return ("Focused on %s, +%d accuracy and +%d%% critical hit chance with ranged attacks against this target."):format(eff.target.name, eff.atk, eff.crit) end,
+	type = "magical",
+	subtype = { tactic=true },
+	status = "beneficial",
+	on_gain = function(self, err) return nil, "+Warden's Focus" end,
+	on_lose = function(self, err) return nil, "-Warden's Focus" end,
+	parameters = { crit=0, atk=0 },
+	on_timeout = function(self, eff)
+		if eff.target.dead or not game.level:hasEntity(self) or not game.level:hasEntity(eff.target) or core.fov.distance(self.x, self.y, eff.target.x, eff.target.y) > 10 then
+			self:removeEffect(self.EFF_WARDEN_S_FOCUS)
+		end
+	end,
+	activate = function(self, eff)	
+	end,
+	deactivate = function(self, eff)
+	end,
+}
+
+newEffect{
+	name = "FATEWEAVER", image = "talents/fateweaver.png",
+	desc = "Fateweaver",
+	long_desc = function(self, eff) return ("The target's accuracy and power have been increased by %d."):format(eff.power_bonus * eff.spin) end,
+	display_desc = function(self, eff) return eff.spin.." Spin" end,
+	charges = function(self, eff) return eff.spin end,
+	type = "magical",
+	subtype = { temporal=true },
+	status = "beneficial",
+	parameters = { power_bonus=0, spin=0, max_spin=3},
+	on_gain = function(self, err) return "#Target# weaves fate.", "+Fateweaver" end,
+	on_lose = function(self, err) return "#Target# stops weaving fate.", "-Fateweaver" end,
+	on_merge = function(self, old_eff, new_eff)
+		-- remove the four old values
+		self:removeTemporaryValue("combat_atk", old_eff.atkid)
+		self:removeTemporaryValue("combat_dam", old_eff.physid)
+		self:removeTemporaryValue("combat_spellpower", old_eff.spellid)
+		self:removeTemporaryValue("combat_mindpower", old_eff.mentalid)
+		
+		-- add some spin
+		old_eff.spin = math.min(old_eff.spin + 1, new_eff.max_spin)
+	
+		-- and apply the current values
+		old_eff.atkid = self:addTemporaryValue("combat_atk", old_eff.power_bonus * old_eff.spin)
+		old_eff.physid = self:addTemporaryValue("combat_dam", old_eff.power_bonus * old_eff.spin)
+		old_eff.spellid = self:addTemporaryValue("combat_spellpower", old_eff.power_bonus * old_eff.spin)
+		old_eff.mentalid = self:addTemporaryValue("combat_mindpower", old_eff.power_bonus * old_eff.spin)
+
+		old_eff.dur = new_eff.dur
+		
+		return old_eff
+	end,
+	activate = function(self, eff)
+		-- apply current values
+		eff.atkid = self:addTemporaryValue("combat_atk", eff.power_bonus * eff.spin)
+		eff.physid = self:addTemporaryValue("combat_dam", eff.power_bonus * eff.spin)
+		eff.spellid = self:addTemporaryValue("combat_spellpower", eff.power_bonus * eff.spin)
+		eff.mentalid = self:addTemporaryValue("combat_mindpower", eff.power_bonus * eff.spin)
+		eff.particle = self:addParticles(Particles.new("arcane_power", 1))
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("combat_atk", eff.atkid)
+		self:removeTemporaryValue("combat_dam", eff.physid)
+		self:removeTemporaryValue("combat_spellpower", eff.spellid)
+		self:removeTemporaryValue("combat_mindpower", eff.mentalid)
+		self:removeParticles(eff.particle)
+	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/timed_effects/other.lua b/game/modules/tome/data/timed_effects/other.lua
index ea0ad7ac7da6fea01f4e1b597d95563095da4483..32956d9f3a0e307b740f49d794c6ccf3571e64b3 100644
--- a/game/modules/tome/data/timed_effects/other.lua
+++ b/game/modules/tome/data/timed_effects/other.lua
@@ -601,22 +601,6 @@ newEffect{
 	end,
 }
 
-newEffect{
-	name = "SPACETIME_STABILITY",
-	desc = "Spacetime Stability",
-	long_desc = function(self, eff) return "Chronomancy spells cast by the target will not fail." end,
-	type = "other",
-	subtype = { time=true },
-	status = "beneficial",
-	parameters = { power=0.1 },
-	on_gain = function(self, err) return "Spacetime has stabilized around #Target#.", "+Spactime Stability" end,
-	on_lose = function(self, err) return "The fabric of spacetime around #Target# has returned to normal.", "-Spacetime Stability" end,
-	activate = function(self, eff)
-	end,
-	deactivate = function(self, eff)
-	end,
-}
-
 newEffect{
 	name = "FADE_FROM_TIME", image = "talents/fade_from_time.png",
 	desc = "Fade From Time",
@@ -2430,12 +2414,14 @@ newEffect{
 	parameters = { power=10},
 	on_gain = function(self, err) return "#Target# retunes the fabric of spacetime.", "+Spacetime Tuning" end,
 	on_timeout = function(self, eff)
-		self:incParadox(eff.power)
+		local dox = self:getParadox() - self.preferred_paradox
+		local fix = math.min( math.abs(dox), eff.power )
+		self:incParadox(fix)
 	end,
 }
 
 newEffect{
-	name = "TIME_STOP", image = "talents/stop.png",
+	name = "TIME_STOP", image = "talents/time_stop.png",
 	desc = "Time Stop",
 	long_desc = function(self, eff)
 		return ("The target has stopped time and is dealing %d%% less damage."):format(eff.power)
@@ -2450,25 +2436,32 @@ newEffect{
 	type = "other",
 	subtype = {time=true},
 	status = "detrimental",
-	--decrease = 0,
-	--no_stop_enter_worlmap = true, no_stop_resting = true,
 	parameters = {power=50},
+	remove_on_clone = true,
 	activate = function(self, eff)
 		self:effectTemporaryValue(eff, "generic_damage_penalty", eff.power)
-		if core.shader.active(4) then
+		if core.shader.allow("volumetric") then
 			eff.particle1, eff.particle2 = self:addParticles3D("volumetric", {kind="vertical_and_awesome", radius=1.4, growSpeed=0.004, img="coggy_00"})
 		end
 		self:effectTemporaryValue(eff, "timestopping", 1)
 		self.no_leave_control = true
 		core.display.pauseAnims(true)
-		self:updateMainShader()
+		
+		-- clone protection
+		if self.player then
+			self:updateMainShader()
+		end
 	end,
 	deactivate = function(self, eff)
 		self.no_leave_control = false
 		core.display.pauseAnims(false)
 		self:removeParticles(eff.particle1)
 		self:removeParticles(eff.particle2)
-		self:updateMainShader()
+		
+		-- clone protection
+		if self == game.player then
+			self:updateMainShader()
+		end
 	end,
 }
 
@@ -2628,8 +2621,8 @@ newEffect{
 }
 
 newEffect{
-	name = "PRESERVE_PATTERN", image = "talents/preserve_pattern.png",
-	desc = "Preserve Pattern",
+	name = "REALITY_SMEARING", image = "talents/reality_smearing.png",
+	desc = "Reality Smearing",
 	long_desc = function(self, eff) return ("Damage received in the past is returned as %0.2f paradox damage per turn."):format(eff.paradox) end,
 	type = "other",
 	subtype = { time=true },
@@ -2714,3 +2707,68 @@ newEffect{
 		self:effectTemporaryValue(eff, "hit_penalty_2h", 1)
 	end,
 }
+
+newEffect{
+	name = "TWIST_FATE", image = "talents/twist_fate.png",
+	desc = "Twist Fate",
+	long_desc = function(self, eff) 
+		local t = self:getTalentFromId(eff.talent)
+		return 
+		([[Currently Twisted Anomlay: %s
+		
+		%s]]):format(t.name or "none", t.info(self, t) or "none")
+	end,
+	type = "other",
+	subtype = { time=true },
+	status = "detrimental",
+	parameters = { paradox=0, twisted=false },
+	on_gain = function(self, err) return nil, "+Twist Fate" end,
+	on_lose = function(self, err) return nil, "-Twist Fate" end,
+	activate = function(self, eff)
+		if core.shader.active(4) then
+			eff.particle1 = self:addParticles(Particles.new("shader_shield", 1, {toback=true,  size_factor=1.5, y=-0.3, img="healcelestial"}, {type="healing", time_factor=4000, noup=2.0, beamColor1={70/255, 130/255, 180/255, 1}, beamColor2={0/255, 0/255, 255/255, 1}, circleColor={0,0,0,0}, beamsCount=5}))
+			eff.particle2 = self:addParticles(Particles.new("shader_shield", 1, {toback=false, size_factor=1.5, y=-0.3, img="healcelestial"}, {type="healing", time_factor=4000, noup=1.0, beamColor1={70/255, 130/255, 180/255, 1}, beamColor2={0/255, 255/255, 255/255, 1}, circleColor={0,0,0,0}, beamsCount=5}))
+		end
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle1)
+		self:removeParticles(eff.particle2)
+		
+		if not game.zone.wilderness and not self.dead then
+			if not eff.twisted then
+				self:forceUseTalent(eff.talent, {force_target=self})
+				game:playSoundNear(self, "talents/dispel")
+				self:incParadox(-eff.paradox)
+			end
+		end
+	end,
+}
+
+newEffect{
+	name = "WARDEN_S_TARGET", image = "talents/warden_s_focus.png",
+	desc = "Warden's Focus Target",
+	long_desc = function(self, eff) return ("The target is being focused on by %s, +%d accuracy and +%d%% critical hit chance with ranged attacks against this target."):format(eff.src.name, eff.atk, eff.crit) end,
+	type = "other",
+	subtype = { tactic=true },
+	status = "detrimental",
+	parameters = {atk = 1, crit= 1},
+	remove_on_clone = true, decrease = 0,
+	on_gain = function(self, err) return nil, "+Warden's Focus" end,
+	on_lose = function(self, err) return nil, "-Warden's Focus" end,
+	on_timeout = function(self, eff)
+		local p = eff.src:hasEffect(eff.src.EFF_WARDEN_S_FOCUS)
+		if not p or p.target ~= self or eff.src.dead or not game.level:hasEntity(eff.src) or core.fov.distance(self.x, self.y, eff.src.x, eff.src.y) > 10 then
+			self:removeEffect(self.EFF_WARDEN_S_TARGET)
+		end
+	end,
+	activate = function(self, eff)
+		if core.shader.active(4) then
+			eff.particle1 = self:addParticles(Particles.new("shader_shield", 1, {toback=true,  size_factor=1.5, y=-0.3, img="healcelestial"}, {type="healing", time_factor=4000, noup=2.0, beamColor1={229/255, 0/255, 0/255, 1}, beamColor2={299/255, 0/255, 0/255, 1}, circleColor={0,0,0,0}, beamsCount=5}))
+			eff.particle2 = self:addParticles(Particles.new("shader_shield", 1, {toback=false, size_factor=1.5, y=-0.3, img="healcelestial"}, {type="healing", time_factor=4000, noup=1.0, beamColor1={229/255, 0/255, 0/255, 1}, beamColor2={229/255, 0/255, 0/255, 1}, circleColor={0.8,0,0,0.8}, beamsCount=5}))
+		end
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle1)
+		self:removeParticles(eff.particle2)
+	end,
+}
diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua
index d1e6fe260b9f7786e3f0d1cd025b435afb02593b..edcf82778071e32c83c6818fe10c4039efe603b6 100644
--- a/game/modules/tome/data/timed_effects/physical.lua
+++ b/game/modules/tome/data/timed_effects/physical.lua
@@ -2832,55 +2832,6 @@ newEffect {
 	end,
 }
 
-newEffect{
-	name = "CELERITY", image = "talents/celerity.png",
-	desc = "Celerity",
-	long_desc = function(self, eff) return ("The target is moving is %d%% faster."):format(eff.speed * 100 * eff.charges) end,
-	type = "physical",
-	display_desc = function(self, eff) return eff.charges.." Celerity" end,
-	charges = function(self, eff) return eff.charges end,
-	subtype = { speed=true, temporal=true },
-	status = "beneficial",
-	parameters = {speed=0.1, charges=1, max_charges=3},
-	on_merge = function(self, old_eff, new_eff)
-		-- remove the old value
-		self:removeTemporaryValue("movement_speed", old_eff.tmpid)
-		
-		-- add a charge
-		old_eff.charges = math.min(old_eff.charges + 1, new_eff.max_charges)
-		
-		-- and apply the current values	
-		old_eff.tmpid = self:addTemporaryValue("movement_speed", old_eff.speed * old_eff.charges)
-		
-		old_eff.dur = new_eff.dur
-		return old_eff
-	end,
-	activate = function(self, eff)
-		eff.tmpid = self:addTemporaryValue("movement_speed", eff.speed * eff.charges)
-	end,
-	deactivate = function(self, eff)
-		self:removeTemporaryValue("movement_speed", eff.tmpid)
-	end,
-}
-
-newEffect{
-	name = "GRAVITY_SLOW", image = "talents/gravity_well.png",
-	desc = "Gravity Slow",
-	long_desc = function(self, eff) return ("The target is caught in a gravity well, reducing movement speed by %d%%."):format(eff.slow* 100) end,
-	type = "physical",
-	subtype = { speed=true },
-	status = "detrimental",
-	parameters = { slow=0.15 },
-	on_gain = function(self, err) return "#Target# is slowed by gravity.", "+Gravity Slow" end,
-	on_lose = function(self, err) return "#Target# is free from the gravity well.", "-Gravity Slow" end,
-	activate = function(self, eff)
-		eff.slowid = self:addTemporaryValue("movement_speed", -eff.slow)
-	end,
-	deactivate = function(self, eff)
-		self:removeTemporaryValue("movement_speed", eff.slowid)
-	end,
-}
-
 newEffect{
 	name = "ANTI_GRAVITY", image = "talents/gravity_locus.png",
 	desc = "Anti-Gravity",
diff --git a/game/modules/tome/data/zones/paradox-plane/npcs.lua b/game/modules/tome/data/zones/paradox-plane/npcs.lua
index 50a855a90d353e5d5f85d8eaed6f381049a6d3e5..48e58c777a8c04582d34eb9881c16581d65e8235 100644
--- a/game/modules/tome/data/zones/paradox-plane/npcs.lua
+++ b/game/modules/tome/data/zones/paradox-plane/npcs.lua
@@ -36,6 +36,7 @@ newEntity{ define_as = "EPOCH",
 	rank = 4,
 
 	can_multiply = 2,
+	anomaly_bias = {type="teleport", chance=100},
 
 	no_breath = 1,
 	poison_immune = 1,
@@ -63,12 +64,15 @@ newEntity{ define_as = "EPOCH",
 
 	resolvers.talents{
 		[Talents.T_MULTIPLY]=1,
-		[Talents.T_TURN_BACK_THE_CLOCK]=3, -- TBTC gets an extra bolt at tl 4, very dangerous
+		[Talents.T_TEMPORAL_BOLT]=3,
+		[Talents.T_DIMENSIONAL_STEP]=5,
 		[Talents.T_CONGEAL_TIME]={base=3, every=7},
-		[Talents.T_DISENTANGLE]=5,
+		[Talents.T_INDUCE_ANOMALY]=5,
 		[Talents.T_BANISH]={base=3, every=7},
+		[Talents.T_TIME_DILATION]={base=3, every=7},
+		[Talents.T_CELERITY]={base=3, every=7},
 		[Talents.T_HASTE]={base=1, every=7},
-		[Talents.T_SWAP]={base=1, every=7},
+		[Talents.T_DIMENSIONAL_STEP]=5,
 	},
 
 	resolvers.sustains_at_birth(),
@@ -82,7 +86,7 @@ newEntity{ define_as = "EPOCH",
 
 	on_multiply = function(self, src)
 		self.on_die = nil
-		self.talents.T_SWAP = nil
+		self.talents.T_DIMENSIONAL_STEP = nil
 		self.talents.T_MULTIPLY = nil
 	end,
 	on_die = function(self, who)
diff --git a/game/modules/tome/data/zones/ruins-kor-pul/npcs.lua b/game/modules/tome/data/zones/ruins-kor-pul/npcs.lua
index f9d47c723e10ad4cb4f6df41204d29b254541e12..b1abbd982137be5958844b7cdd94b4fa1a8112fd 100644
--- a/game/modules/tome/data/zones/ruins-kor-pul/npcs.lua
+++ b/game/modules/tome/data/zones/ruins-kor-pul/npcs.lua
@@ -58,7 +58,7 @@ newEntity{ define_as = "SHADE",
 	stats = { str=16, dex=12, cun=14, mag=25, con=16 },
 	instakill_immune = 1,
 	blind_immune = 1,
-	bleed_immune = 1,
+	cut_immune = 1,
 	move_others=true,
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
@@ -141,7 +141,7 @@ newEntity{ define_as = "KOR_FURY",
 	stone_immune = 1,
 	confusion_immune = 1,
 	fear_immune = 1,
-	bleed_immune = 1,
+	cut_immune = 1,
 	teleport_immune = 0.5,
 	disease_immune = 1,
 	poison_immune = 1,
diff --git a/game/modules/tome/data/zones/temporal-rift/npcs.lua b/game/modules/tome/data/zones/temporal-rift/npcs.lua
index a12c8d523f3fa0df2d0f4d532b68f6719f17e02b..576da5bb87b7b468ea01aef4640018d9d57e8446 100644
--- a/game/modules/tome/data/zones/temporal-rift/npcs.lua
+++ b/game/modules/tome/data/zones/temporal-rift/npcs.lua
@@ -167,7 +167,7 @@ newEntity{ base="BASE_NPC_HORROR_TEMPORAL", define_as = "CHRONOLITH_TWIN",
 		[Talents.T_DESTABILIZE]=3,
 		[Talents.T_ECHOES_FROM_THE_PAST]=3,
 		[Talents.T_HASTE]=3,
-		[Talents.T_DISENTANGLE]=5,
+		[Talents.T_INDUCE_ANOMALY]=5,
 		[Talents.T_ENERGY_ABSORPTION]=5,
 		[Talents.T_REPULSION_FIELD]=5,
 	},
@@ -217,7 +217,7 @@ newEntity{ base="BASE_NPC_HORROR_TEMPORAL", define_as = "CHRONOLITH_CLONE",
 		[Talents.T_TURN_BACK_THE_CLOCK]=3,
 		[Talents.T_HASTE]=3,
 		[Talents.T_BANISH]=5,
-		[Talents.T_DISENTANGLE]=5,
+		[Talents.T_INDUCE_ANOMALY]=5,
 		[Talents.T_ENTROPIC_FIELD]=5,
 	},
 
diff --git a/game/modules/tome/data/zones/town-point-zero/npcs.lua b/game/modules/tome/data/zones/town-point-zero/npcs.lua
index b4b797e530062858f986d4c7448d160e30eb7bbd..012389bffc21582a337535e9dd545cbea0830e67 100644
--- a/game/modules/tome/data/zones/town-point-zero/npcs.lua
+++ b/game/modules/tome/data/zones/town-point-zero/npcs.lua
@@ -173,26 +173,27 @@ newEntity{ base = "BASE_NPC_POINT_ZERO_TOWN", define_as = "ZEMEKKYS",
 		[Talents.T_LUCKY_DAY]=1,
 		[Talents.T_ENDLESS_WOES]=1,
 		[Talents.T_EYE_OF_THE_TIGER]=1,
-		[Talents.T_GATHER_THE_THREADS]=5,
+		
 		[Talents.T_RETHREAD]=5,
-		[Talents.T_TEMPORAL_CLONE]=5,
+		[Talents.T_TEMPORAL_FUGUE]=5,
+
+		[Talents.T_SPACETIME_STABILITY]=5,
 		[Talents.T_STOP]=5,
-		[Talents.T_SLOW]=5,
+		[Talents.T_CHRONO_TIME_SHIELD]=5,
+		[Talents.T_STATIC_HISTORY]=5,
+		
+		[Talents.T_CELERITY]=5,
+		[Talents.T_TIME_DILATION]=5,
 		[Talents.T_HASTE]=5,
-		[Talents.T_BANISH]=5,
-		[Talents.T_PARADOX_MASTERY]=5,
-		[Talents.T_FADE_FROM_TIME]=5,
-		[Talents.T_DUST_TO_DUST]=5,
-		[Talents.T_QUANTUM_SPIKE]=5,
+		
 		[Talents.T_REPULSION_BLAST]=5,
 		[Talents.T_GRAVITY_SPIKE]=5,
-		[Talents.T_REPULSION_FIELD]=5,
+		[Talents.T_GRAVITY_LOCUS]=5,
 		[Talents.T_GRAVITY_WELL]=5,
+		
 		[Talents.T_ENTROPY]=5,
 		[Talents.T_ENERGY_ABSORPTION]=5,
 		[Talents.T_REDUX]=5,
-		[Talents.T_TEMPORAL_FUGUE]=5,
-		[Talents.T_BODY_REVERSION]=5,
 	},
 	resolvers.sustains_at_birth(),
 }
diff --git a/game/modules/tome/data/zones/unhallowed-morass/npcs.lua b/game/modules/tome/data/zones/unhallowed-morass/npcs.lua
index 55ff8f879007384f15aabfd7550d0c908567fe6d..d862487d06a542c6db12da9541e7034aba991e21 100644
--- a/game/modules/tome/data/zones/unhallowed-morass/npcs.lua
+++ b/game/modules/tome/data/zones/unhallowed-morass/npcs.lua
@@ -38,6 +38,22 @@ newEntity{
 	combat_armor = 1, combat_def = 1,
 }
 
+newEntity{ base = "BASE_NPC_SPIDER",
+	name = "weaver hatchling", color=colors.LIGHT_STEEL_BLUE, image="npc/spiderkin_spider_weaver_young.png",
+	desc = [[A nearly translucent spider hatchling.]],
+	level_range = {1, nil}, exp_worth = 1,
+	rarity = 1,	size_category = 1,
+	max_life = resolvers.rngavg(10,20),
+	combat_armor = 1, combat_def = 3,
+	combat = { dam=resolvers.levelup(5, 1, 0.7), atk=5, apr=3, damtype=DamageType.WASTING, },
+	make_escort = {
+		{type = "spiderkin", subtype = "spider", name="weaver hatchling", number=2, no_subescort=true},
+	},
+	resolvers.talents{
+		[Talents.T_DIMENSIONAL_STEP]=1,
+	},
+}
+
 newEntity{ base = "BASE_NPC_SPIDER",
 	name = "orb spinner", color=colors.UMBER,
 	desc = [[A large brownish arachnid, its fangs drip with a strange fluid.]],
@@ -45,59 +61,63 @@ newEntity{ base = "BASE_NPC_SPIDER",
 	rarity = 1,
 	max_life = resolvers.rngavg(20,40),
 	combat_armor = 1, combat_def = 3,
-	combat = { dam=resolvers.levelup(5, 1, 0.7), atk=15, apr=3, damtype=DamageType.CLOCK, },
+	combat = { dam=resolvers.levelup(5, 1, 0.7), atk=5, apr=3, damtype=DamageType.TEMPORAL, },
+	resolvers.talents{
+		[Talents.T_TEMPORAL_BOLT]=1,
+	},
+	make_escort = {
+		{type = "spiderkin", subtype = "spider", name="orb weaver", number=1, no_subescort=true},
+	},
 }
 
 newEntity{ base = "BASE_NPC_SPIDER",
 	name = "orb weaver", color=colors.DARK_UMBER,
 	desc = [[A large brownish arachnid spinning its web.  It doesn't look pleased that you've disturbed its work.]],
 	level_range = {3, nil}, exp_worth = 1,
-	rarity = 3,
+	rarity = 10, -- rarely appears alone
 	max_life = resolvers.rngavg(40,60),
 	combat_armor =2, combat_def = 4,
-	combat = { dam=resolvers.levelup(6, 1, 0.8), atk=15, apr=3, damtype=DamageType.TEMPORAL, },
+	combat = { dam=resolvers.levelup(6, 1, 0.8), atk=10, apr=3, damtype=DamageType.TEMPORAL, },
 	resolvers.talents{
 		[Talents.T_LAY_WEB]=1,
-		[Talents.T_DIMENSIONAL_STEP]=1,
+		[Talents.T_SPIDER_WEB]=1,
 	},
 }
 
 newEntity{ base = "BASE_NPC_SPIDER",
 	name = "fate spinner", color=colors.SLATE,
 	desc = [[Easily as big as a horse, this giant spider menaces at you with claws and fangs.]],
-	level_range = {4, nil}, exp_worth = 1,
-	rarity = 3,
+	level_range = {3, nil}, exp_worth = 1,
+	rarity = 2, rank = 2,
 	size_category = 4,
-	max_life = resolvers.rngavg(60,70),
+	max_life = resolvers.rngavg(70,100),
 	combat_armor = 3, combat_def = 5,
-	combat = { dam=resolvers.levelup(9, 1, 0.9), atk=15, apr=4, damtype=DamageType.CLOCK, },
+	combat = { dam=resolvers.levelup(9, 1, 0.9), atk=15, apr=4, damtype=DamageType.WASTING, },
 	resolvers.talents{
-		[Talents.T_LAY_WEB]=1,
-		[Talents.T_SPIDER_WEB]=1,
 		[Talents.T_DIMENSIONAL_STEP]=1,
-		[Talents.T_TURN_BACK_THE_CLOCK]=1,
+		[Talents.T_WARP_MINE_TOWARD]=1,
 	},
 }
 
 newEntity{ base = "BASE_NPC_SPIDER",
 	name = "fate weaver", color=colors.WHITE,
 	desc = [[A large white spider.]],
-	level_range = {4, nil}, exp_worth = 1,
-	rarity = 3,
+	level_range = {3, nil}, exp_worth = 1,
+	rarity = 3, rank = 2,
 	max_life = resolvers.rngavg(70,100),
 	combat_armor = 3, combat_def = 4,
-	combat = { dam=resolvers.levelup(8, 1, 0.9), atk=15, apr=3, damtype=DamageType.WASTING, },
+	combat = { dam=resolvers.levelup(8, 1, 0.9), atk=15, apr=3, damtype=DamageType.TEMPORAL, },
 	
-	talent_cd_reduction = {[Talents.T_RETHREAD]=-10},
-
 	resolvers.talents{
 		[Talents.T_SPIN_FATE]=1,
-		[Talents.T_RETHREAD]=2,
+		[Talents.T_WEBS_OF_FATE]=1,
+		[Talents.T_FATEWEAVER]=1,
+		[Talents.T_RETHREAD]=1,
 	},
 }
 
 newEntity{ base = "BASE_NPC_SPIDER", define_as = "WEAVER_QUEEN",
-	name = "Weaver Queen", color=colors.WHITE,
+	name = "Weaver Queen", color=colors.WHITE, female=1,
 	resolvers.nice_tile{image="invis.png", add_mos = {{image="npc/spiderkin_spider_weaver_queen.png", display_h=2, display_y=-1}}},
 	desc = [[A large white spider.]],
 	level_range = {7, nil}, exp_worth = 1,
@@ -119,14 +139,22 @@ newEntity{ base = "BASE_NPC_SPIDER", define_as = "WEAVER_QUEEN",
 	inc_damage = {all=-20},
 	healing_factor = 0.5,
 	
-	talent_cd_reduction = {[Talents.T_RETHREAD]=-10},
-
+	summon = {{type = "spiderkin", subtype = "spider", name="weaver hatchling", number=1, hasxp=false}},
+	
 	resolvers.talents{
-		[Talents.T_SPIN_FATE]=1,
-		[Talents.T_BANISH]=2,
-		[Talents.T_RETHREAD]=2,
-		[Talents.T_FADE_FROM_TIME]=3,
+		[Talents.T_SPIN_FATE]=2,
+		[Talents.T_WEBS_OF_FATE]=2,
+		[Talents.T_FATEWEAVER]=2,
+		[Talents.T_PHASE_PULSE]=2,
+		[Talents.T_SUMMON]=1,
+		[Talents.T_TEMPORAL_BOLT]=1,	
 	},
+	
+	on_move = function(self)
+		if rng.percent(50) then
+			self:forceUseTalent(self.T_ANOMALY_WORMHOLE, {silent=true, ignore_energy=true})
+		end
+	end,
 
 	autolevel = "caster",
 	ai = "tactical", ai_state = { talent_in=1, ai_move="move_astar", },
diff --git a/game/modules/tome/dialogs/talents/ChronomancyEmpower.lua b/game/modules/tome/dialogs/talents/ChronomancyEmpower.lua
index d32047643cf3fa00498516580b07fb227ee38b14..73133cd53ba1fbcd47ae3b19fe6ec2a153dfb042 100644
--- a/game/modules/tome/dialogs/talents/ChronomancyEmpower.lua
+++ b/game/modules/tome/dialogs/talents/ChronomancyEmpower.lua
@@ -37,6 +37,20 @@ local function TalentStatus(who,t)
 	return tostring(status) 
 end
 
+-- check if the talent is already bound to another sustain
+local function spellbound(who, t)
+	for tid, active in pairs(who.sustain_talents) do
+		if active then
+			local tt = who:getTalentFromId(tid)
+			if tt.type[1]:find("^chronomancy/spellbinding") then
+				if who:isTalentActive(tid).talent == t then
+					return true
+				end
+			end
+		end
+	end
+end
+
 function _M:init(actor)
 	self.actor = actor
 	actor.hotkey = actor.hotkey or {}
@@ -105,7 +119,7 @@ function _M:generateList()
 
 	-- Generate lists of all talents by category
 	for j, t in pairs(self.actor.talents_def) do
-		if self.actor:knowTalent(t.id) and t.type[1]:find("^chronomancy/") and not t.type[1]:find("^chronomancy/spellbinding") and not t.hide and t.mode ~= "passive" then
+		if self.actor:knowTalent(t.id) and t.type[1]:find("^chronomancy/") and not t.type[1]:find("^chronomancy/spellbinding") and not t.hide and t.mode ~= "passive" and not spellbound(self.actor, t.id) then
 			local nodes = talents
 			local status = tstring{{"color", "LIGHT_GREEN"}, "Talents"}
 			
diff --git a/game/modules/tome/dialogs/talents/ChronomancyExtension.lua b/game/modules/tome/dialogs/talents/ChronomancyExtension.lua
index aeebefbb07b2ddfec017fec9221c278c63b19434..3007d5e5f3eca3a5d9339117bdbfe46d0980b963 100644
--- a/game/modules/tome/dialogs/talents/ChronomancyExtension.lua
+++ b/game/modules/tome/dialogs/talents/ChronomancyExtension.lua
@@ -37,6 +37,20 @@ local function TalentStatus(who,t)
 	return tostring(status) 
 end
 
+-- check if the talent is already bound to another sustain
+local function spellbound(who, t)
+	for tid, active in pairs(who.sustain_talents) do
+		if active then
+			local tt = who:getTalentFromId(tid)
+			if tt.type[1]:find("^chronomancy/spellbinding") then
+				if who:isTalentActive(tid).talent == t then
+					return true
+				end
+			end
+		end
+	end
+end
+
 function _M:init(actor)
 	self.actor = actor
 	actor.hotkey = actor.hotkey or {}
@@ -105,7 +119,7 @@ function _M:generateList()
 
 	-- Generate lists of all talents by category
 	for j, t in pairs(self.actor.talents_def) do
-		if self.actor:knowTalent(t.id) and t.type[1]:find("^chronomancy/") and not t.type[1]:find("^chronomancy/spellbinding") and not t.hide and t.getDuration and t.mode ~= "passive" then
+		if self.actor:knowTalent(t.id) and t.type[1]:find("^chronomancy/") and not t.type[1]:find("^chronomancy/spellbinding") and not t.hide and t.getDuration and t.mode ~= "passive" and not spellbound(self.actor, t.id) then
 			local nodes = talents
 			local status = tstring{{"color", "LIGHT_GREEN"}, "Talents"}
 			
diff --git a/game/modules/tome/dialogs/talents/ChronomancyMatrix.lua b/game/modules/tome/dialogs/talents/ChronomancyMatrix.lua
index d676fb3f0086c5ed4e1457a48daa69b9c2e3a261..eb258adafe67f60c3134e7b5d34efa189475259b 100644
--- a/game/modules/tome/dialogs/talents/ChronomancyMatrix.lua
+++ b/game/modules/tome/dialogs/talents/ChronomancyMatrix.lua
@@ -37,6 +37,20 @@ local function TalentStatus(who,t)
 	return tostring(status) 
 end
 
+-- check if the talent is already bound to another sustain
+local function spellbound(who, t)
+	for tid, active in pairs(who.sustain_talents) do
+		if active then
+			local tt = who:getTalentFromId(tid)
+			if tt.type[1]:find("^chronomancy/spellbinding") then
+				if who:isTalentActive(tid).talent == t then
+					return true
+				end
+			end
+		end
+	end
+end
+
 function _M:init(actor)
 	self.actor = actor
 	actor.hotkey = actor.hotkey or {}
@@ -105,7 +119,7 @@ function _M:generateList()
 
 	-- Generate lists of all talents by category
 	for j, t in pairs(self.actor.talents_def) do
-		if self.actor:knowTalent(t.id) and t.type[1]:find("^chronomancy/") and not t.type[1]:find("^chronomancy/spellbinding") and not t.hide and t.cooldown and t.mode ~= "passive" and not t.fixed_cooldown then
+		if self.actor:knowTalent(t.id) and t.type[1]:find("^chronomancy/") and not t.type[1]:find("^chronomancy/spellbinding") and not t.hide and t.cooldown and t.mode ~= "passive" and not t.fixed_cooldownand and not spellbound(self.actor, t.id) then
 			local nodes = talents
 			local status = tstring{{"color", "LIGHT_GREEN"}, "Talents"}
 			
diff --git a/game/modules/tome/dialogs/talents/ChronomancyQuicken.lua b/game/modules/tome/dialogs/talents/ChronomancyQuicken.lua
index d970a67f2f093274cf817e29f26860a369facc71..701d7b783adccb681beffa7e54ed08a2b0fcc3b2 100644
--- a/game/modules/tome/dialogs/talents/ChronomancyQuicken.lua
+++ b/game/modules/tome/dialogs/talents/ChronomancyQuicken.lua
@@ -37,6 +37,20 @@ local function TalentStatus(who,t)
 	return tostring(status) 
 end
 
+-- check if the talent is already bound to another sustain
+local function spellbound(who, t)
+	for tid, active in pairs(who.sustain_talents) do
+		if active then
+			local tt = who:getTalentFromId(tid)
+			if tt.type[1]:find("^chronomancy/spellbinding") then
+				if who:isTalentActive(tid).talent == t then
+					return true
+				end
+			end
+		end
+	end
+end
+
 function _M:init(actor)
 	self.actor = actor
 	actor.hotkey = actor.hotkey or {}
@@ -105,7 +119,7 @@ function _M:generateList()
 
 	-- Generate lists of all talents by category
 	for j, t in pairs(self.actor.talents_def) do
-		if self.actor:knowTalent(t.id) and t.type[1]:find("^chronomancy/") and not t.type[1]:find("^chronomancy/spellbinding") and not t.hide and not t.no_energy and t.mode ~= "passive" then
+		if self.actor:knowTalent(t.id) and t.type[1]:find("^chronomancy/") and not t.type[1]:find("^chronomancy/spellbinding") and not t.hide and not t.no_energy and t.mode ~= "passive" and not spellbound(self.actor, t.id) then
 			local nodes = talents
 			local status = tstring{{"color", "LIGHT_GREEN"}, "Talents"}