diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua
index 22f81d4e4ba1a739c26914e802fb280dc12f7a9d..d8ae4ac2c59a87ebbbe4d8dee4d35f2c133948b6 100644
--- a/game/modules/tome/class/interface/Combat.lua
+++ b/game/modules/tome/class/interface/Combat.lua
@@ -1155,13 +1155,14 @@ end
 -- y_low = value to match at x_low
 -- y_high = value to match at x_high
 -- power = scaling factor (default 0.5)
-function _M:combatScale(x, y_low, x_low, y_high, x_high, power)
-	power = power or 0.5
-	local x_low_adj, x_high_adj = x_low^power, x_high^power
+-- add = amount to add the result (default 0)
+-- shift = amount to add to the input value before computation (default 0)
+function _M:combatScale(x, y_low, x_low, y_high, x_high, power, add, shift)
+	power, add, shift = power or 0.5, add or 0, shift or 0
+	local x_low_adj, x_high_adj = (x_low+shift)^power, (x_high+shift)^power
 	local m = (y_high - y_low)/(x_high_adj - x_low_adj)
 	local b = y_low - m*x_low_adj
-	return m * x^power + b
---	return m * x^power + b, m, b
+	return m * (x + shift)^power + b + add
 end
 
 -- Scale a value up or down subject to a limit
diff --git a/game/modules/tome/data/talents/celestial/chants.lua b/game/modules/tome/data/talents/celestial/chants.lua
index 1d3710782e96a3a29b3cd144f485685898acad00..b8b0f3573c6a66cd28f09a9db7a3fef319692d6a 100644
--- a/game/modules/tome/data/talents/celestial/chants.lua
+++ b/game/modules/tome/data/talents/celestial/chants.lua
@@ -172,7 +172,7 @@ newTalent{
 	range = 10,
 	getLightDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
 	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
-	getLite = function(self, t) return 1 + math.floor(self:getTalentLevelRaw(t)) end,
+	getLite = function(self, t) return math.floor(self:combatTalentScale(t, 2, 6, "log")) end,
 	activate = function(self, t)
 		cancelChants(self)
 		game:playSoundNear(self, "talents/spell_generic2")
diff --git a/game/modules/tome/data/talents/celestial/circles.lua b/game/modules/tome/data/talents/celestial/circles.lua
index ec6f7638cb013155f025be9dbde99543fd447e91..55a1bb9b7fff10e5a2924230706a86ad9180552b 100644
--- a/game/modules/tome/data/talents/celestial/circles.lua
+++ b/game/modules/tome/data/talents/celestial/circles.lua
@@ -28,11 +28,9 @@ newTalent{
 	no_energy = true,
 	tactical = { DEFEND = 2, ATTACKAREA = {DARKNESS = 1} },
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 4, 30) end,
-	getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 4, 8)) end,
 	range = 0,
-	radius = function(self, t)
-		return 2 + math.floor(self:getTalentLevelRaw(t)/2)
-	end,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
 	end,
@@ -69,11 +67,9 @@ newTalent{
 	no_energy = true,
 	tactical = { DEFEND = 2, ATTACKAREA = {FIRE = 0.5, LIGHT = 0.5} },
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 2, 15) end,
-	getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 4, 8)) end,
 	range = 0,
-	radius = function(self, t)
-		return 2 + math.floor(self:getTalentLevelRaw(t)/2)
-	end,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
 	end,
@@ -113,11 +109,9 @@ newTalent{
 	negative = 10,
 	no_energy = true,
 	tactical = { DEFEND = 2, ATTACKAREA = 1 },
-	getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 4, 8)) end,
 	range = 0,
-	radius = function(self, t)
-		return 2 + math.floor(self:getTalentLevelRaw(t)/2)
-	end,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
 	end,
@@ -152,11 +146,9 @@ newTalent{
 	negative = 10,
 	no_energy = true,
 	tactical = { DEFEND = 2, ATTACKAREA = {LIGHT = 0.5, DARKNESS = 0.5} },
-	getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 4, 8)) end,
 	range = 0,
-	radius = function(self, t)
-		return 2 + math.floor(self:getTalentLevelRaw(t)/2)
-	end,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
 	end,
diff --git a/game/modules/tome/data/talents/celestial/combat.lua b/game/modules/tome/data/talents/celestial/combat.lua
index 7de64a6e4fc6b88539bf98d302a19621c1d115ef..d66cd20f7702134ae6d66bd331a385d40963d47d 100644
--- a/game/modules/tome/data/talents/celestial/combat.lua
+++ b/game/modules/tome/data/talents/celestial/combat.lua
@@ -27,7 +27,7 @@ newTalent{
 	sustain_positive = 10,
 	tactical = { BUFF = 2 },
 	range = 10,
-	getDamage = function(self, t) return 7 + self:combatSpellpower(0.092) * self:getTalentLevel(t) end,
+	getDamage = function(self, t) return 7 + self:combatSpellpower(0.092) * self:combatTalentScale(t, 1, 5) end,
 	activate = function(self, t)
 		game:playSoundNear(self, "talents/spell_generic2")
 		local ret = {
@@ -58,7 +58,7 @@ newTalent{
 	range = 6,
 	reflectable = true,
 	requires_target = true,
-	getReturnDamage = function(self, t) return 8 * self:getTalentLevelRaw(t) end,
+	getReturnDamage = function(self, t) return self:combatLimit(self:getTalentLevel(t)^.5, 100, 15, 1, 40, 2.24) end, -- Limit <100%
 	action = function(self, t)
 		local tg = {type="bolt", range=self:getTalentRange(t), talent=t}
 		local x, y = self:getTarget(tg)
@@ -90,7 +90,7 @@ newTalent{
 	positive = 10,
 	tactical = { ATTACK = 2 },
 	requires_target = true,
-	range = function(self, t) return 2 + self:getStr(8) end,
+	range = function(self, t) return 2 + math.max(0, self:combatStatScale("str", 0.8, 8)) end,
 	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 1.9) end,
 	action = function(self, t)
 		local tg = {type="bolt", range=self:getTalentRange(t), talent=t}
diff --git a/game/modules/tome/data/talents/celestial/eclipse.lua b/game/modules/tome/data/talents/celestial/eclipse.lua
index 8bfafacccf9c6d696b520176846917d0e0949296..e78dd2b669eeceba31ef0f6540ddaed78a2c574f 100644
--- a/game/modules/tome/data/talents/celestial/eclipse.lua
+++ b/game/modules/tome/data/talents/celestial/eclipse.lua
@@ -23,15 +23,13 @@ newTalent{
 	mode = "passive",
 	require = divi_req1,
 	points = 5,
-	on_learn = function(self, t)
-		self.combat_spellcrit = self.combat_spellcrit + 3
-	end,
-	on_unlearn = function(self, t)
-		self.combat_spellcrit = self.combat_spellcrit - 3
+	getCrit = function(self, t) return self:combatTalentScale(t, 3, 15, 0.75) end,
+	passives = function(self, t, p)
+		self:talentTemporaryValue(p, "combat_spellcrit", t.getCrit(self, t))
 	end,
 	info = function(self, t)
 		return ([[Increases your spell critical chance by %d%%.]]):
-		format(3 * self:getTalentLevelRaw(t))
+		format(t.getCrit(self, t))
 	end,
 }
 
@@ -44,9 +42,9 @@ newTalent{
 	tactical = { BUFF = 2 },
 	positive = 10,
 	negative = 10,
-	getDuration = function(self, t) return 4 + math.ceil(self:getTalentLevel(t)) end,
-	getResistancePenetration = function(self, t) return 5 + (self:getCun() / 10) * self:getTalentLevel(t) end,
-	getCooldownReduction = function(self, t) return 1 + math.ceil(self:getTalentLevel(t)) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9)) end,
+	getResistancePenetration = function(self, t) return self:combatLimit(self:getCun()*self:getTalentLevel(t), 100, 5, 0, 55, 500) end, -- Limit to <100%
+	getCooldownReduction = function(self, t) return math.floor(self:combatTalentScale(t, 2, 6)) end,
 	action = function(self, t)
 		self:setEffect(self.EFF_TOTALITY, t.getDuration(self, t), {power=t.getResistancePenetration(self, t)})
 		for tid, cd in pairs(self.talents_cd) do
@@ -79,7 +77,7 @@ newTalent{
 	tactical = { BUFF = 2 },
 	sustain_negative = 10,
 	sustain_positive = 10,
-	getTargetCount = function(self, t) return math.floor(self:getTalentLevel(t)) end,
+	getTargetCount = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5)) end,
 	getLightDamage = function(self, t) return self:combatTalentSpellDamage(t, 15, 70) end,
 	getDarknessDamage = function(self, t) return self:combatTalentSpellDamage(t, 15, 70) end,
 	on_crit = function(self, t)
@@ -142,10 +140,10 @@ newTalent{
 	cooldown = 30,
 	sustain_negative = 10,
 	tactical = { DEFEND = 2, ESCAPE = 2 },
-	getInvisibilityPower = function(self, t) return 5 + (self:getCun() / 15) * self:getTalentLevel(t) end,
+	getInvisibilityPower = function(self, t) return self:combatScale(self:getCun() * self:getTalentLevel(t), 5, 0, 38.33, 500) end,
 	getEnergyConvert = function(self, t) return math.max(0, 6 - self:getTalentLevelRaw(t)) end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 100) end,
-	getRadius = function(self, t) return 2 + self:getTalentLevel(t) / 2 end,
+	getRadius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	activate = function(self, t)
 		local timer = t.getEnergyConvert(self, t)
 		game:playSoundNear(self, "talents/heal")
diff --git a/game/modules/tome/data/talents/celestial/glyphs.lua b/game/modules/tome/data/talents/celestial/glyphs.lua
index 2afb5319364f12479d5511bbe2020a6c56c584af..31346e63fa10244a5294f220871609f0102f5f4d 100644
--- a/game/modules/tome/data/talents/celestial/glyphs.lua
+++ b/game/modules/tome/data/talents/celestial/glyphs.lua
@@ -30,9 +30,10 @@ newTalent{
 	no_energy = true,
 	requires_target = true,
 	tactical = { DISABLE = 2 },
-	range = function(self, t) return math.floor (self:getTalentLevel(t)) end,
-	getDazeDuration = function(self, t) return 3 + self:getTalentLevelRaw(t) end,
-	getDuration = function(self, t) return 5 + self:getTalentLevel(t) end,
+	range = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5, "log")) end,
+	getDazeDuration = function(self, t) return math.floor(self:combatTalentScale(t, 4, 8)) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 6, 10)) end, -- Duration of glyph
+	trapPower = function(self,t) return math.max(1,self:combatScale(self:getTalentLevel(t) * self:getMag(15, true), 0, 0, 75, 75)) end, -- Used to determine detection and disarm power, about 75 at level 50
 	action = function(self, t)
 		local tg = {type="hit", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t}
 		local tx, ty = self:getTarget(tg)
@@ -59,6 +60,8 @@ newTalent{
 			end,
 			temporary = t.getDuration(self, t),
 			x = tx, y = ty,
+			disarm_power = math.floor(t.trapPower(self,t)),
+			detect_power = math.floor(t.trapPower(self,t) * 0.8),
 			canAct = false,
 			energy = {value=0},
 			act = function(self)
@@ -82,8 +85,8 @@ newTalent{
 	info = function(self, t)
 		local dazeduration = t.getDazeDuration(self, t)
 		local duration = t.getDuration(self, t)
-		return ([[You bind light in a glyph on the floor. All targets walking over the glyph will be dazed for %d turns.
-		The glyph lasts for %d turns.]]):format(dazeduration, duration)
+		return ([[You bind light in a glyph on the floor. All enemies walking over the glyph will be dazed for %d turns.
+		The glyph is a hidden trap (%d detection and %d disarm power based on your Magic) and lasts for %d turns.]]):format(dazeduration, t.trapPower(self,t)*0.8, t.trapPower(self,t), duration)
 	end,
 }
 
@@ -98,9 +101,10 @@ newTalent{
 	no_energy = true,
 	tactical = { DISABLE = 2 },
 	requires_target = true,
-	range = function(self, t) return math.floor (self:getTalentLevel(t)) end,
-	getDamage = function(self, t) return 15 + self:combatSpellpower(0.12) * self:getTalentLevel(t) end,
-	getDuration = function(self, t) return 5 + self:getTalentLevel(t) end,
+	range = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5, "log")) end,
+	getDamage = function(self, t) return 15 + self:combatSpellpower(0.12) * self:combatTalentScale(t, 1.5, 5) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 6, 10)) end, -- Duration of glyph
+	trapPower = function(self,t) return math.max(1,self:combatScale(self:getTalentLevel(t) * self:getMag(15, true), 0, 0, 75, 75)) end, -- Used to determine detection and disarm power, about 75 at level 50
 	action = function(self, t)
 		local tg = {type="hit", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t}
 		local tx, ty = self:getTarget(tg)
@@ -130,6 +134,10 @@ newTalent{
 			end,
 			temporary = t.getDuration(self, t),
 			x = tx, y = ty,
+			disarm_power = math.floor(t.trapPower(self,t)),
+			detect_power = math.floor(t.trapPower(self,t) * 0.8),
+			inc_damage = table.clone(self.inc_damage or {}, true),
+			resists_pen = table.clone(self.resists_pen or {}, true),
 			canAct = false,
 			energy = {value=0},
 			combatSpellpower = function(self) return self.sp end, sp = sp,
@@ -154,10 +162,10 @@ newTalent{
 	info = function(self, t)
 		local damage = t.getDamage(self, t)
 		local duration = t.getDuration(self, t)
-		return ([[You bind light in a glyph on the floor. All targets walking over the glyph will be hit by a blast that knocks them back and does %0.2f damage.
-		The glyph lasts for %d turns.
+		return ([[You bind light in a glyph on the floor. All targets walking over the glyph will be hit by a blast that knocks them back and does %0.2f physical damage.
+		The glyph is a hidden trap (%d detection and %d disarm power based on your Magic) and lasts for %d turns.
 		The damage will increase with your Spellpower.]]):
-		format(damDesc(self, DamageType.LIGHT, damage), duration)
+		format(damDesc(self, DamageType.SPELLKNOCKBACK, damage), t.trapPower(self, t)*0.8, t.trapPower(self, t), duration)
 	end,
 }
 
@@ -172,9 +180,10 @@ newTalent{
 	no_energy = true,
 	tactical = { ATTACKAREA = {LIGHT = 2} },
 	requires_target = true,
-	range = function(self, t) return math.floor (self:getTalentLevel(t)) end,
-	getDamage = function(self, t) return 15 + self:combatSpellpower(0.12) * self:getTalentLevel(t) end,
-	getDuration = function(self, t) return 5 + self:getTalentLevel(t) end,
+	range = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5, "log")) end,
+	getDamage = function(self, t) return 15 + self:combatSpellpower(0.12) * self:combatTalentScale(t, 1.5, 5) end,-- Should this be higher than glyph of repulsion?
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 6, 10)) end, -- Duration of glyph
+	trapPower = function(self,t) return math.max(1,self:combatScale(self:getTalentLevel(t) * self:getMag(15, true), 0, 0, 75, 75)) end, -- Used to determine detection and disarm power, about 75 at level 50
 	action = function(self, t)
 		local tg = {type="hit", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t}
 		local tx, ty = self:getTarget(tg)
@@ -200,6 +209,10 @@ newTalent{
 			end,
 			temporary = t.getDuration(self, t),
 			x = tx, y = ty,
+			disarm_power = math.floor(t.trapPower(self,t) * 0.8),
+			detect_power = math.floor(t.trapPower(self,t) * 0.8),
+			inc_damage = table.clone(self.inc_damage or {}, true),
+			resists_pen = table.clone(self.resists_pen or {}, true),
 			canAct = false,
 			energy = {value=0},
 			act = function(self)
@@ -224,9 +237,9 @@ newTalent{
 		local damage = t.getDamage(self, t)
 		local duration = t.getDuration(self, t)
 		return ([[You bind light in a glyph on the floor. All targets walking over the glyph will trigger an explosion of light that does %0.2f damage to everyone within 1 tile.
-		The glyph lasts for %d turns.
+		The glyph is a hidden trap (%d detection and %d disarm power based on your Magic) and lasts for %d turns.
 		The damage will increase with your Spellpower.]]):
-		format(damDesc(self, DamageType.LIGHT, damage), duration)
+		format(damDesc(self, DamageType.LIGHT, damage), t.trapPower(self, t)*0.8, t.trapPower(self, t)*0.8, duration)
 	end,
 }
 
@@ -241,9 +254,10 @@ newTalent{
 	no_energy = true,
 	tactical = { DISABLE = 2 },
 	requires_target = true,
-	range = function(self, t) return math.floor (self:getTalentLevel(t)) end,
-	getSlow = function(self, t) return math.min(self:getTalentLevel(t) * 0.07 + 0.2, 0.65) end,
-	getDuration = function(self, t) return 5 + self:getTalentLevel(t) end,
+	range = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5, "log")) end,
+	getSlow = function(self, t) return self:combatTalentLimit(t, 100, 0.27, 0.55) end, -- Limit <100% slow
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 6, 10)) end, -- Duration of glyph
+	trapPower = function(self,t) return math.max(1,self:combatScale(self:getTalentLevel(t) * self:getMag(15, true), 0, 0, 75, 75)) end, -- Used to determine detection and disarm power, about 75 at level 50
 	action = function(self, t)
 		local tg = {type="hit", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t}
 		local tx, ty = self:getTarget(tg)
@@ -268,6 +282,8 @@ newTalent{
 			end,
 			temporary = t.getDuration(self, t),
 			x = tx, y = ty,
+			disarm_power = math.floor(t.trapPower(self,t)),
+			detect_power = math.floor(t.trapPower(self,t)),
 			canAct = false,
 			energy = {value=0},
 			act = function(self)
@@ -292,6 +308,7 @@ newTalent{
 		local slow = t.getSlow(self, t)
 		local duration = t.getDuration(self, t)
 		return ([[You bind light in a glyph on the floor. All targets walking over the glyph will be slowed by %d%% for 5 turns.
-		The glyph lasts for %d turns.]]):format(100 * slow, duration)
+		The glyph is a hidden trap (%d detection and %d disarm power based on your Magic) and lasts for %d turns.]]):
+		format(100 * slow, t.trapPower(self, t), t.trapPower(self, t), duration)
 	end,
 }
diff --git a/game/modules/tome/data/talents/celestial/guardian.lua b/game/modules/tome/data/talents/celestial/guardian.lua
index ceb719d8fc15acf9b617b507233e78727db836c3..5544798ed0b108671cda6c2e565d66b5dc9395f3 100644
--- a/game/modules/tome/data/talents/celestial/guardian.lua
+++ b/game/modules/tome/data/talents/celestial/guardian.lua
@@ -64,9 +64,7 @@ newTalent{
 	getWeaponDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
 	getShieldDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5, self:getTalentLevel(self.T_SHIELD_EXPERTISE)) end,
 	getLightDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 200) end,
-	radius = function(self, t)
-		return 2 + self:getTalentLevel(t) / 2
-	end,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	action = function(self, t)
 		local shield = self:hasShield()
 		if not shield then
@@ -115,7 +113,7 @@ newTalent{
 	mode = "sustained",
 	sustain_positive = 20,
 	cooldown = 10,
-	range = function(self, t) return 1 + self:getTalentLevelRaw(t) end,
+	range = function(self, t) return math.floor(self:combatTalentScale(t, 2, 6)) end,
 	tactical = { DEFEND = 2 },
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 40, 400) end,
 	activate = function(self, t)
@@ -155,7 +153,7 @@ newTalent{
 	sustain_positive = 60,
 	cooldown = 50,
 	tactical = { DEFEND = 2 },
-	getLife = function(self, t) return self.max_life * (0.05 + self:getTalentLevel(t)/25) end,
+	getLife = function(self, t) return self.max_life * self:combatTalentLimit(t, 1.5, 0.09, 0.25) end, -- Limit < 150% max life (to survive a large string of hits between turns)
 	activate = function(self, t)
 		game:playSoundNear(self, "talents/heal")
 		local ret = {
diff --git a/game/modules/tome/data/talents/celestial/hymns.lua b/game/modules/tome/data/talents/celestial/hymns.lua
index b4ba41282b03ef2712ce7b6885f788da8c0017fb..c3fb9084e4265a1a946d50a14b17f5bc3f542641 100644
--- a/game/modules/tome/data/talents/celestial/hymns.lua
+++ b/game/modules/tome/data/talents/celestial/hymns.lua
@@ -82,7 +82,7 @@ newTalent{
 	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
 	getSeeInvisible = function(self, t) return self:combatTalentSpellDamage(t, 2, 35) end,
 	getSeeStealth = function(self, t) return self:combatTalentSpellDamage(t, 2, 15) end,
-	getInfraVisionPower = function(self, t) return math.floor(5 + self:getTalentLevel(t)) end,
+	getInfraVisionPower = function(self, t) return math.floor(self:combatTalentScale(t, 6, 10)) end,
 	activate = function(self, t)
 		cancelHymns(self)
 		game:playSoundNear(self, "talents/spell_generic2")
@@ -129,7 +129,7 @@ newTalent{
 	tactical = { BUFF = 2 },
 	range = 10,
 	getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
-	getImmunities = function(self, t) return 0.15 + self:getTalentLevel(t) / 14 end,
+	getImmunities = function(self, t) return self:combatTalentLimit(t, 1, 0.22, 0.5) end, -- Limit < 100%
 	activate = function(self, t)
 		cancelHymns(self)
 		local dam = self:combatTalentSpellDamage(t, 5, 25)
@@ -175,8 +175,8 @@ newTalent{
 	tactical = { BUFF = 2 },
 	range = 5,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 7, 80) end,
-	getTargetCount = function(self, t) return math.floor(self:getTalentLevel(t)) end,
-	getNegativeDrain = function(self, t) return 9 - self:getTalentLevelRaw(t) end,
+	getTargetCount = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5)) end,
+	getNegativeDrain = function(self, t) return self:combatTalentLimit(t, 0, 8, 3) end, -- Limit > 0, no regen at high levels
 	do_beams = function(self, t)
 		if self:getNegative() < t.getNegativeDrain(self, t) then return end
 
@@ -222,7 +222,7 @@ newTalent{
 		local drain = t.getNegativeDrain(self, t)
 		return ([[Chant the glory of the Moon, conjuring a shroud of dancing shadows that follows you as long as this spell is active.
 		Each turn, a shadowy beam will hit up to %d of your foes within radius 5 for 1 to %0.2f damage.
-		This powerful spell will drain %d negative energy for each beam; no beam will fire if your negative energy is too low.
+		This powerful spell will drain %0.1f negative energy for each beam; no beam will fire if your negative energy is too low.
 		The damage will increase with your Spellpower.]]):
 		format(targetcount, damDesc(self, DamageType.DARKNESS, damage), drain)
 	end,
diff --git a/game/modules/tome/data/talents/celestial/light.lua b/game/modules/tome/data/talents/celestial/light.lua
index 6b55ec78692d143887f57021d44eb03c103133be..da3147fb0ea0f8c6b839f0305d81266bb5fe04b3 100644
--- a/game/modules/tome/data/talents/celestial/light.lua
+++ b/game/modules/tome/data/talents/celestial/light.lua
@@ -58,7 +58,7 @@ newTalent{
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
 	end,
 	getHeal = function(self, t) return self:combatTalentSpellDamage(t, 4, 40) end,
-	getDuration = function(self, t) return self:getTalentLevel(t) + 2 end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3, 7)) end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		self:project(tg, self.x, self.y, DamageType.LITE, 1)
@@ -118,7 +118,7 @@ newTalent{
 	cooldown = 30,
 	tactical = { HEAL = 1, CURE = 2 },
 	getRegeneration = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
-	getDuration = function(self, t) return 2 + math.ceil(self:getTalentLevel(t)) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3, 7)) end,
 	action = function(self, t)
 		self:setEffect(self.EFF_PROVIDENCE, t.getDuration(self, t), {power=t.getRegeneration(self, t)})
 		game:playSoundNear(self, "talents/heal")
diff --git a/game/modules/tome/data/talents/celestial/star-fury.lua b/game/modules/tome/data/talents/celestial/star-fury.lua
index cadd8baf7c7e43cd24890e92c182b72d92cb5d4b..167edfdf98c03d16f0091e65c370c29796eaa183 100644
--- a/game/modules/tome/data/talents/celestial/star-fury.lua
+++ b/game/modules/tome/data/talents/celestial/star-fury.lua
@@ -70,7 +70,7 @@ newTalent{
 	end,
 	getDamageOnSpot = function(self, t) return self:combatTalentSpellDamage(t, 4, 40) end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 5, 110) end,
-	getDuration = function(self, t) return math.floor(self:getTalentLevel(t) * 0.8) + 2 end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 2.8, 6)) end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
@@ -118,8 +118,8 @@ newTalent{
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, selffire=false}
 	end,
-	getLightDamage = function(self, t) return 10 + self:combatSpellpower(0.2) * self:getTalentLevel(t) end,
-	getDarknessDamage = function(self, t) return 10 + self:combatSpellpower(0.2) * self:getTalentLevel(t) end,
+	getLightDamage = function(self, t) return 10 + self:combatSpellpower(0.2) * self:combatTalentScale(t, 1, 5) end,
+	getDarknessDamage = function(self, t) return 10 + self:combatSpellpower(0.2) * self:combatTalentScale(t, 1, 5) end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local grids = self:project(tg, self.x, self.y, DamageType.LIGHT, self:spellCrit(t.getLightDamage(self, t)))
@@ -134,7 +134,6 @@ newTalent{
 		local darknessdam = t.getDarknessDamage(self, t)
 		local radius = self:getTalentRadius(t)
 		return ([[A surge of twilight pulses from you, doing %0.2f light and %0.2f darkness damage to all others within radius %d.
-		This skill also increases both your positive and negative energy.
 		The damage dealt will increase with your Spellpower.]]):
 		format(damDesc(self, DamageType.LIGHT, lightdam),damDesc(self, DamageType.DARKNESS, darknessdam), radius)
 	end,
@@ -150,9 +149,7 @@ newTalent{
 	negative = 20,
 	tactical = { ATTACKAREA = {DARKNESS = 2}, DISABLE = 2 },
 	range = 6,
-	radius = function(self, t)
-		return 1 + math.floor(self:getTalentLevelRaw(t) / 3)
-	end,
+	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)
diff --git a/game/modules/tome/data/talents/celestial/sun.lua b/game/modules/tome/data/talents/celestial/sun.lua
index fb5b7b25a3836f6b5cf8ff0fa604cb8edb052e7f..9adadb421a9df65d49ad981cf8524eaf0d4657aa 100644
--- a/game/modules/tome/data/talents/celestial/sun.lua
+++ b/game/modules/tome/data/talents/celestial/sun.lua
@@ -72,14 +72,12 @@ newTalent{
 	tactical = { ATTACKAREA = {LIGHT = 1}, DISABLE = 2 },
 	direct_hit = true,
 	range = 0,
-	radius = function(self, t)
-		return 2 + math.ceil(self:getTalentLevel(t) / 2)
-	end,
+	radius = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 4.5)) end,
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), selffire=false, radius=self:getTalentRadius(t), talent=t}
 	end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 4, 80) end,
-	getDuration = function(self, t) return 3 + self:getTalentLevel(t) end,
+	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 4, 8)) end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		-- Temporarily turn on "friendlyfire" to lite all tiles
diff --git a/game/modules/tome/data/talents/celestial/twilight.lua b/game/modules/tome/data/talents/celestial/twilight.lua
index 601d46170bfc41f3ece4eea2a5cecd836ba8efc7..cc14c56b2e0d92c732815342777646cecc1012b3 100644
--- a/game/modules/tome/data/talents/celestial/twilight.lua
+++ b/game/modules/tome/data/talents/celestial/twilight.lua
@@ -28,8 +28,8 @@ newTalent{
 	positive = 15,
 	tactical = { BUFF = 1 },
 	range = 10,
-	getRestValue = function(self, t) return 17 + math.floor(3.5 * self:getTalentLevel(t)) end,
-	getNegativeGain = function(self, t) return 20 + self:getTalentLevel(t) * self:getCun(40, true) end,
+	getRestValue = function(self, t) return self:combatTalentLimit(t, 50, 20.5, 34.5) end, -- Limit < 50%
+	getNegativeGain = function(self, t) return math.max(0, self:combatScale(self:getTalentLevel(t) * self:getCun(40, true), 24, 4, 220, 200, nil, nil, 40)) end,
 	passives = function(self, t, p)
 		self:talentTemporaryValue(p, "positive_at_rest", t.getRestValue(self, t))
 		self:talentTemporaryValue(p, "negative_at_rest", t.getRestValue(self, t))
@@ -45,8 +45,8 @@ newTalent{
 	end,
 	info = function(self, t)
 		return ([[You stand between the darkness and the light, allowing you to convert 15 positive energy into %d negative energy.
-		In addition, this will change the default level of positive and negative energies to %d%% of their maximum. Each turn, the energies will slowly fall/rise to this value, instead of 0.
-		The effect will increase with your Cunning.]]):
+		Learning this talent will change the default level of positive and negative energies to %d%% of their maximum. Each turn, the energies will slowly fall/rise to this value, instead of 0.
+		The negative energy gain will increase with your Cunning.]]):
 		format(t.getNegativeGain(self, t), t.getRestValue(self, t))
 	end,
 }
@@ -61,7 +61,7 @@ newTalent{
 	tactical = { ESCAPE = 2 },
 	no_npc_use = true,
 	no_unlearn_last = true,
-	getRange = function(self, t) return math.floor(10 + 3 * self:getTalentLevel(t)) end,
+	getRange = function(self, t) return math.floor(self:combatTalentScale(t, 13, 18)) end,
 	-- Check distance in preUseTalent to grey out the talent
 	on_pre_use = function(self, t)
 		local eff = self.sustain_talents[self.T_JUMPGATE]
@@ -91,7 +91,14 @@ newTalent{
 	require = divi_req2,
 	mode = "sustained", no_sustain_autoreset = true,
 	points = 5,
-	cooldown = function(self, t) return 24 - 4 * self:getTalentLevelRaw(t) end,
+	cooldown = function(self, t)
+		local tl = self:getTalentLevelRaw(t)
+		if tl < 4 then
+			return math.ceil(self:combatLimit(tl, 0, 20, 1, 8, 4))
+		else
+			return math.ceil(self:combatLimit(tl, 0, 8, 4, 4, 5)) --I5 Limit >0
+		end
+	end,
 	sustain_negative = 20,
 	no_npc_use = true,
 	tactical = { ESCAPE = 2 },
@@ -156,8 +163,8 @@ newTalent{
 	target = function(self, t)
 		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, selffire=false}
 	end,
-	getConfuseDuration = function(self, t) return math.floor(self:getTalentLevel(t) + self:getCun(5)) + 2 end,
-	getConfuseEfficency = function(self, t) return 50 + self:getTalentLevelRaw(t)*10 end,
+	getConfuseDuration = function(self, t) return math.floor(self:combatScale(self:getTalentLevel(t) + self:getCun(5), 2, 0, 12, 10)) end,
+	getConfuseEfficency = function(self, t) return self:combatTalentLimit(t, 60, 15, 45) end, -- Limit < 60% (slightly better than most confusion effects)
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		self:project(tg, self.x, self.y, DamageType.CONFUSION, {
@@ -169,9 +176,9 @@ newTalent{
 	end,
 	info = function(self, t)
 		local duration = t.getConfuseDuration(self, t)
-		return ([[Let out a mental cry that shatters the will of your targets within radius 3, confusing them for %d turns.
+		return ([[Let out a mental cry that shatters the will of your targets within radius 3, confusing (%d%% to act randomly) them for %d turns.
 		The duration will improve with your Cunning.]]):
-		format(duration)
+		format(t.getConfuseEfficency(self,t),duration)
 	end,
 }
 
@@ -187,7 +194,8 @@ newTalent{
 	requires_target = true,
 	range = 5,
 	no_npc_use = true,
-	getDuration = function(self, t) return math.ceil(self:getTalentLevel(t)+self:getCun(10)) + 3 end,
+	getDuration = function(self, t) return math.floor(self:combatScale(self:getTalentLevel(t)+self:getCun(10), 3, 0, 18, 15)) end,
+	getPercent = function(self, t) return self:combatScale(self:getCun(10, true) * self:getTalentLevel(t), 0, 0, 50, 50) end,
 	action = function(self, t)
 		local tg = {type="bolt", range=self:getTalentRange(t), talent=t}
 		local tx, ty, target = self:getTarget(tg)
@@ -218,7 +226,7 @@ newTalent{
 			return true
 		end
 
-		modifier = self:getCun(10, true) * self:getTalentLevel(t)
+		local modifier = t.getPercent(self, t)
 
 		local m = target:clone{
 			shader = "shadow_simulacrum",
@@ -236,7 +244,7 @@ newTalent{
 		m.on_added_to_level = nil
 
 		m.energy.value = 0
-		m.life = m.life / (2 - math.min(modifier / 50, 1.9))
+		m.life = m.life*modifier/100
 		m.forceLevelup = function() end
 		-- Handle special things
 		m.on_die = nil
@@ -258,16 +266,18 @@ newTalent{
 	info = function(self, t)
 		local duration = t.getDuration(self, t)
 		local allowed = 2 + math.ceil(self:getTalentLevelRaw(t) / 2 )
+		local size = "gargantuan"
 		if allowed < 4 then
 			size = "medium"
 		elseif allowed < 5 then
 			size = "big"
-		else
+		elseif allowed < 6 then
 			size = "huge"
 		end
-		return ([[Creates a shadowy copy of a target of up to %s size. The copy will attack its progenitor immediately.
-		It stays for %d turns; its duration, life and resistances scale with your Cunning.]]):
-		format(size, duration)
+		return ([[Creates a shadowy copy of a hostile target of up to %s size. The copy will attack its progenitor immediately and lasts for %d turns.
+		The duplicate has %d%% of the target's life, %d%% all damage resistance, +50%% darkness resistance and -50%% light resistance.
+		The duration, life and all damage resistance scale with your Cunning and this ability will not work on bosses.]]):
+		format(size, duration, t.getPercent(self, t), t.getPercent(self, t))
 	end,
 }
 
@@ -334,7 +344,7 @@ newTalent{
 	type_no_req = true,
 	tactical = { ESCAPE = 2 },
 	no_npc_use = true,
-	getRange = function(self, t) return math.floor(10 + 3 * self:getTalentLevel(t)) end,
+	getRange = function(self, t) return self:callTalent(self.T_JUMPGATE_TELEPORT, "getRange") end,
 	-- Check distance in preUseTalent to grey out the talent
 	is_teleport = true,
 	no_unlearn_last = true,