diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 1fb5cb51e4eb5e5fa274358577d3793a12d1c25b..7400c153caf805437b50004960385420f07d7877 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -133,6 +133,7 @@ function _M:init(t, no_default)
 	t.stamina_rating = t.stamina_rating or 3
 	t.positive_negative_rating = t.positive_negative_rating or 3
 	t.psi_rating = t.psi_rating or 0
+	t.inc_resource_multi = t.inc_resource_multi or {}
 
 	t.esp = t.esp or {}
 	t.esp_range = t.esp_range or 10
@@ -1694,7 +1695,7 @@ function _M:onTakeHit(value, src)
 		if self:knowTalent(self.T_BACKLASH) then
 			if src.y and src.x and not src.dead then
 				local t = self:getTalentFromId(self.T_BACKLASH)
-				t.doBacklash(self, src, t)
+				t.doBacklash(self, src, feedback_gain, t)
 			end
 		end
 	end
@@ -2411,13 +2412,22 @@ function _M:levelup()
 end
 
 --- Notifies a change of stat value
+-- Note inc_resource_multi does not auto-update and talents that use it should manually adjust the pools
 function _M:onStatChange(stat, v)
 	if stat == self.STAT_CON then
-		self.max_life = self.max_life + 4 * v
+		-- life
+		local multi_life = 4 + (self.inc_resource_multi.life or 0)
+		self.max_life = self.max_life + multi_life * v
 	elseif stat == self.STAT_WIL then
-		self:incMaxMana(5 * v)
-		self:incMaxStamina(2.5 * v)
-		self:incMaxPsi(1 * v)
+		-- mana
+		local multi_mana = 5 + (self.inc_resource_multi.mana or 0)
+		self:incMaxMana(multi_mana * v)
+		-- stamina
+		local multi_stamina = 2.5 + (self.inc_resource_multi.stamina or 0)
+		self:incMaxStamina(multi_stamina * v)
+		-- psi
+		local multi_psi = 1 + (self.inc_resource_multi.psi or 0)
+		self:incMaxPsi(multi_psi * v)
 	elseif stat == self.STAT_STR then
 		self:checkEncumbrance()
 	end
@@ -3216,6 +3226,7 @@ function _M:preUseTalent(ab, silent, fake)
 		end
 		if ab.psi and self:getPsi() < ab.psi * (100 + 2 * self:combatFatigue()) / 100 then
 			if not silent then game.logPlayer(self, "You do not have enough energy to use %s.", ab.name) end
+			return false
 		end
 		if ab.feedback and self:getFeedback() < ab.feedback * (100 + 2 * self:combatFatigue()) / 100 then
 			if not silent then game.logPlayer(self, "You do not have enough feedback to use %s.", ab.name) end
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index 8bdad5e15b0db75769ab0661f88029c46610d269..b558ad11ee390945895c925f89edd65f48f20a2a 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -79,6 +79,7 @@ function _M:init(t, no_default)
 	t.rank = t.rank or 3
 	t.old_life = 0
 	t.old_air = 0
+	t.old_psi = 0
 
 	t.money_value_multiplier = t.money_value_multiplier or 1 -- changes amounts in gold piles and such
 
@@ -258,6 +259,7 @@ function _M:act()
 
 	self.old_life = self.life
 	self.old_air = self.air
+	self.old_psi = self.psi
 
 	-- Clean log flasher
 --	game.flash:empty()
@@ -300,7 +302,12 @@ function _M:updateMainShader()
 			if self.air < self.max_air / 2 then game.fbo_shader:setUniform("air_warning", 1 - (self.air / self.max_air))
 			else game.fbo_shader:setUniform("air_warning", 0) end
 		end
-
+		if self:attr("solipsism_threshold") and self.psi ~= self.old_psi then
+			local solipsism_power = self:attr("solipsism_threshold") - self:getPsi()/self:getMaxPsi()
+			if solipsism_power > 0 then game.fbo_shader:setUniform("solipsism_warning", solipsism_power)
+			else game.fbo_shader:setUniform("solipsism_warning", 0) end
+		end
+			
 		-- Colorize shader
 		if self:attr("stealth") then game.fbo_shader:setUniform("colorize", {0.9,0.9,0.9,0.6})
 		elseif self:attr("invisible") then game.fbo_shader:setUniform("colorize", {0.3,0.4,0.9,0.8})
diff --git a/game/modules/tome/class/interface/TooltipsData.lua b/game/modules/tome/class/interface/TooltipsData.lua
index 19a0b5677581bc93abc6f9799f4c192abb2562cb..aedd9d1106fa6432da4531b5d54a6044aa4cc565 100644
--- a/game/modules/tome/class/interface/TooltipsData.lua
+++ b/game/modules/tome/class/interface/TooltipsData.lua
@@ -295,6 +295,9 @@ TOOLTIP_SPELL_COOLDOWN = [[#GOLD#Spellcooldown#LAST#
 Spell cooldown represents how fast your spells will come off of cooldown.
 The lower it is the more often you'll be able to use your spell talents and runes.
 ]]
+-------------------------------------------------------------
+-- Mental
+-------------------------------------------------------------
 TOOLTIP_MINDPOWER = [[#GOLD#Mindpower#LAST#
 Your mindpower value represents how powerful your mental abilities are.
 In addition, when your mental abilities inflict temporary detrimental effects, every point your opponent's relevant saving throw exceeds your  mindpower will reduce the duration of the effect by 5%.
@@ -304,7 +307,10 @@ Each time you deal damage with a mental attack you may have a chance to make a c
 Some talents allow you to increase this percentage.
 It is improved by Cunning.
 ]]
-
+TOOLTIP_MIND_SPEED = [[#GOLD#Mental speed#LAST#
+Mental speed represents how fast you use psionic abilities compared to a normal turn.
+The lower it is the faster it is.
+]]
 -------------------------------------------------------------
 -- Damage and resists
 -------------------------------------------------------------
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index 7d86b48ad7dd85a4b5caf8104dbdfb66518cc843..8cd369c24acad180b151fa23a3611fcaf3299e87 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -2099,7 +2099,8 @@ newDamageType{
 			if target:hasEffect(target.EFF_DISTORTION) then
 				-- Explosive?
 				if dam.explosion then
-					src:project({type="ball", target.x, target.y, radius=dam.radius}, target.x, target.y, engine.DamageType.DISTORTION, {dam=src:mindCrit(dam.explosion)}, {type="mind"})
+					src:project({type="ball", target.x, target.y, radius=dam.radius}, target.x, target.y, engine.DamageType.DISTORTION, {dam=src:mindCrit(dam.explosion)})
+					game.level.map:particleEmitter(target.x, target.y, dam.radius, "generic_blast", {radius=dam.radius, tx=target.x, ty=target.y, rm=255, rM=255, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 					dam.explosion_done = true
 				end
 				-- Stun?
diff --git a/game/modules/tome/data/gfx/particles/charge.lua b/game/modules/tome/data/gfx/particles/charge.lua
index c944b4acd78cb1d6b7d8aa31e51ddf61ecac37d8..c2bf2d34d032f0e280275ffe66379981d1d44fd7 100644
--- a/game/modules/tome/data/gfx/particles/charge.lua
+++ b/game/modules/tome/data/gfx/particles/charge.lua
@@ -17,35 +17,35 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
-base_size = 32
-
 return { generator = function()
-	local life = rng.range(10, 20)
-	local size = rng.range(15, 20)
-	local angle = math.rad(rng.range(0, 360))
-	local distance = engine.Map.tile_w * rng.float(2, 2.5)
-	local vel = distance / life
+	local radius = 0
+	local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+	local ad = rng.float(0, 360)
+	local a = math.rad(ad + 180)
+	local r = rng.float(0, sradius / 4)
+	local x = r * math.cos(a)
+	local y = r * math.sin(a)
+	local bx = math.floor(x / engine.Map.tile_w)
+	local by = math.floor(y / engine.Map.tile_h)
+	local static = rng.percent(40)
 
 	return {
 		trail = 1,
-		life = life,
-		size = size, sizev = 0.2, sizea = 0,
+		life = 2,
+		size = 12, sizev = 0, sizea = 0,
 
-		x = -size / 2 + distance * math.cos(angle), xv = 0, xa = 0,
-		y = -size / 2 + distance * math.sin(angle), yv = 0, ya = 0,
-		dir = angle, dirv = 0, dira = 0,
-		vel = -vel, velv = 0, vela = 0,
+		x = x, xv = 0, xa = 0,
+		y = y, yv = 0, ya = 0,
+		dir = a, dirv = 0, dira = 0,
+		vel = sradius / 2 / 24, velv = 0, vela = 0,
 
-		r = rng.range(200, 255) / 255,  rv = 0, ra = 0,
-		g = rng.range(200, 255) / 255,  gv = 0, ga = 0,
-		b = rng.range(200, 255) / 255,  bv = 0, ba = 0,
-		a = 0.5,  av = 0.01, aa = 0,
+		r = rng.range(255, 255)/255,  rv = 0, ra = 0,
+		g = rng.range(180, 230)/255,  gv = 0, ga = 0,
+		b = 0,                        bv = 0, ba = 0,
+		a = rng.range(25, 220)/255,   av = 0, aa = 0,
 	}
 end, },
 function(self)
-	self.nb = (self.nb or 0) + 1
-	if self.nb < 6 then
-		self.ps:emit(10)
-	end
+	self.ps:emit(5)
 end,
-120
+5*2
\ No newline at end of file
diff --git a/game/modules/tome/data/gfx/particles/charge_matter.lua b/game/modules/tome/data/gfx/particles/charge_matter.lua
index 07cb090c326e89e29f1dcfdccf81f5d4c28c7b62..23e730639257f65e10de01a8d605b7fb0ab2eac5 100644
--- a/game/modules/tome/data/gfx/particles/charge_matter.lua
+++ b/game/modules/tome/data/gfx/particles/charge_matter.lua
@@ -1,4 +1,4 @@
--- ToME - Tales of Maj'Eyal
+-- ToME - Tales of Middle-Earth
 -- Copyright (C) 2009, 2010, 2011, 2012 Nicolas Casalini
 --
 -- This program is free software: you can redistribute it and/or modify
@@ -17,36 +17,41 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
-base_size = 32
+local nb = 0
 
 return { generator = function()
-	local life = rng.range(10, 20)
-	local size = rng.range(15, 20)
-	local angle = math.rad(rng.range(0, 360))
-	local distance = engine.Map.tile_w * rng.float(2, 2.5)
-	local vel = distance / life
-
+	local radius = 0
+	local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+	local ad = rng.float(0, 360)
+	local a = math.rad(ad)
+	local r = rng.float(0.1, sradius / 2)
+	local x = r * math.cos(a)
+	local y = r * math.sin(a)
+	local bx = math.floor(x / engine.Map.tile_w)
+	local by = math.floor(y / engine.Map.tile_h)
+	local static = rng.percent(40)
+	
 	return {
 		trail = 1,
-		life = life,
-		size = size, sizev = 0.2, sizea = 0,
+		life = 3 + 9 * (sradius - r) / sradius,
+		size = 3, sizev = 0, sizea = 0,
+
+		x = x, xv = 0, xa = 0,
+		y = y, yv = 0, ya = 0,
+		dir = 0, dirv = 0, dira = 0,
+		vel = 0, velv = 0, vela = 0,
 
-		x = -size / 2 + distance * math.cos(angle), xv = 0, xa = 0,
-		y = -size / 2 + distance * math.sin(angle), yv = 0, ya = 0,
-		
-		dir = angle, dirv = 0, dira = 0,
-		vel = -vel, velv = 0, vela = 0,
 
-		r = rng.range(10, 110)/255,  	rv = 0, ra = 0,
-		g = rng.range(10, 50)/255,   	gv = 0.005, ga = 0.0005,
-		b = rng.range(20, 125)/255,     bv = 0, ba = 0,
-		a = rng.range(25, 255)/255,    	av = static and -0.034 or 0, aa = 0.005,
+		r = rng.range(255, 255)/255, 		rv = 0.005, ra = 0.0005,
+		g = rng.range(180, 255)/255,	 	gv = 0.005, ga = 0.0005,
+		b = rng.range(180, 255)/255,		bv = 0.005, ba = 0.0005,
+		a = rng.range(200, 255)/255,  		av = static and -0.034 or 0, aa = 0.005,
 	}
 end, },
 function(self)
-	self.nb = (self.nb or 0) + 1
-	if self.nb < 6 then
-		self.ps:emit(10)
+	if nb < 1 then
+		self.ps:emit(40)
 	end
+	nb = nb + 1
 end,
-120
+40
diff --git a/game/modules/tome/data/gfx/particles/generic_ball.lua b/game/modules/tome/data/gfx/particles/generic_ball.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ac538407e87d309365ed0effc94c1b9b5328652d
--- /dev/null
+++ b/game/modules/tome/data/gfx/particles/generic_ball.lua
@@ -0,0 +1,63 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012 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
+
+local nb = 0
+return { generator = function()
+	local radius = radius
+	local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+	local ad = rng.float(0, 360)
+	local a = math.rad(ad)
+	local r = rng.float(0, sradius / 2)
+	local x = r * math.cos(a)
+	local y = r * math.sin(a)
+	local bx = math.floor(x / engine.Map.tile_w)
+	local by = math.floor(y / engine.Map.tile_h)
+	local static = rng.percent(40)
+
+	return {
+		trail = 1,
+		life = 30,
+		size = 3, sizev = 0, sizea = 0,
+
+		x = x, xv = 0, xa = 0,
+		y = y, yv = 0, ya = 0,
+		dir = a, dirv = 0, dira = 0,
+		vel = sradius / 2 / 30, velv = 0, vela = 0,
+		
+		r = rng.range(rm, rM)/255,    rv = 0, ra = 0,
+		g = rng.range(gm, gM)/255,	  gv = 0, ga = 0,
+		b = rng.range(bm, bM)/255,	  bv = 0, ba = 0,
+		a = rng.range(am, aM)/255,    av = 0.01, aa = 0,
+	}
+end, },
+function(self)
+	if nb < 5 then
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+	end
+end,
+5*radius*266
diff --git a/game/modules/tome/data/gfx/particles/generic_wave.lua b/game/modules/tome/data/gfx/particles/generic_wave.lua
new file mode 100644
index 0000000000000000000000000000000000000000..d23851ca39b259f8b0ffb630f022db95c19eef49
--- /dev/null
+++ b/game/modules/tome/data/gfx/particles/generic_wave.lua
@@ -0,0 +1,63 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012 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
+
+local nb = 12
+local dir = 0
+local spread = spread or 55/2
+local radius = radius or 6
+
+dir = math.deg(math.atan2(ty, tx))
+
+return { generator = function()
+	local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+	local ad = rng.float(dir - spread, dir + spread)
+	local a = math.rad(ad)
+	local r = 0
+	local x = r * math.cos(a)
+	local y = r * math.sin(a)
+	local static = rng.percent(40)
+	local vel = sradius * ((24 - nb * 1.4) / 24) / 6
+
+	return {
+		trail = 0,
+		life = 6,
+		size = 12 - (12 - nb) * 0.7, sizev = 0, sizea = 2,
+
+		x = x, xv = 0, xa = 0,
+		y = y, yv = 0, ya = 0,
+		dir = a, dirv = 0, dira = 0,
+		vel = rng.float(vel * 0.6, vel * 1.2), velv = 0, vela = 0,
+
+
+		r = rng.range(rm, rM)/255,  	rv = 0.005, ra = 0.0005,
+		g = rng.range(gm, gM)/255, 	 	gv = 0.005, ga = 0.0005,
+		b = rng.range(bm, bM)/255, 		bv = 0.005, ba = 0.0005,
+		a = rng.range(am, aM)/255, 		av = 0, aa = 0,
+	}
+end, },
+function(self)
+	if nb > 0 then
+		local i = math.min(nb, 6)
+		i = (i * i) * radius
+		self.ps:emit(i)
+		nb = nb - 1
+	end
+end,
+30*radius*7*12,
+"particle_cloud"
diff --git a/game/modules/tome/data/gfx/shaders/main_fbo.frag b/game/modules/tome/data/gfx/shaders/main_fbo.frag
index d72f7c363eba4e476fa92ff04866910f09ce879f..d169b8d944e9da97d6dcee13ddce5ce931f61fb7 100644
--- a/game/modules/tome/data/gfx/shaders/main_fbo.frag
+++ b/game/modules/tome/data/gfx/shaders/main_fbo.frag
@@ -1,5 +1,6 @@
 uniform float hp_warning;
 uniform float air_warning;
+uniform float solipsism_warning;
 uniform float motionblur;
 uniform float blur;
 uniform float tick;
@@ -121,6 +122,13 @@ void main(void)
 		float dist = length(gl_TexCoord[0].xy - vec2(0.5)) / 2.0;
 		gl_FragColor = mix(gl_FragColor, air_warning_color, dist);
 	}
+	
+	if (solipsism_warning > 0.0)
+	{
+		vec4 solipsism_warning_color = vec4(solipsism_warning / 2.0, 0.0, solipsism_warning / 2.0, solipsism_warning / 1.3);
+		float dist = length(gl_TexCoord[0].xy - vec2(0.5)) / 2.0;
+		gl_FragColor = mix(gl_FragColor, solipsism_warning_color, dist);
+	}
 }
 
 /*uniform sampler2D tex;
diff --git a/game/modules/tome/data/talents/chronomancy/energy.lua b/game/modules/tome/data/talents/chronomancy/energy.lua
index fa797b84ba9ca3178970e1deb4ea6b434517b06a..b6fc8150f7e397de7c2732e4164fda5c3b146e4a 100644
--- a/game/modules/tome/data/talents/chronomancy/energy.lua
+++ b/game/modules/tome/data/talents/chronomancy/energy.lua
@@ -142,8 +142,8 @@ newTalent{
 			end
 		end
 		target:crossTierEffect(target.EFF_SPELLSHOCKED, self:combatSpellpower())
-		game.level.map:particleEmitter(tx, ty, 1, "charge_matter")
-		game.level.map:particleEmitter(self.x, self.y, 1, "charge")
+		game.level.map:particleEmitter(tx, ty, 1, "generic_charge", {rm=10, rM=110, gm=10, gM=50, bm=20, bM=125, am=25, aM=255})
+		game.level.map:particleEmitter(self.x, self.y, 1, "generic_charge", {rm=200, rM=255, gm=200, gM=255, bm=200, bM=255, am=125, aM=125})
 		game:playSoundNear(self, "talents/spell_generic")
 		return true
 	end,
diff --git a/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua b/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
index 95ae1c406915cfb05a8fa62edb6f5ed4be89896f..29eaa632cdb4e764805776f1da76bbc48d9f6e07 100644
--- a/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
+++ b/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
@@ -243,6 +243,7 @@ newTalent{
 				end
 			end,
 		}
+		entrance.faction = nil
 		game.level:addEntity(entrance)
 		entrance:identify(true)
 		entrance:setKnown(self, true)
diff --git a/game/modules/tome/data/talents/psionic/discharge.lua b/game/modules/tome/data/talents/psionic/discharge.lua
index 8b1b163a91f21984c8572b29de58047b5b00d9a5..53e0a4184ddf6c2e0b44a785fa38cb0043babf0e 100644
--- a/game/modules/tome/data/talents/psionic/discharge.lua
+++ b/game/modules/tome/data/talents/psionic/discharge.lua
@@ -17,7 +17,7 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles
+-- Edge TODO: Sounds
 
 newTalent{
 	name = "Backlash",
@@ -30,24 +30,29 @@ newTalent{
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), talent=t}
 	end,
-	doBacklash = function(self, target, t)
+	doBacklash = function(self, target, value, t)
 		if core.fov.distance(self.x, self.y,target.x, target.y) > self:getTalentRange(t) then return nil end
 		local tg = self:getTalentTarget(t)
 		local a = game.level.map(target.x, target.y, Map.ACTOR)
 		if not a or self:reactionToward(a) >= 0 then return nil end
+		local damage = math.min(value, t.getDamage(self, t))
 		-- Divert the Backlash?
 		local wrath = self:hasEffect(self.EFF_FOCUSED_WRATH)
-		if wrath then
-			self:project(tg, wrath.target.x, wrath.target.y, DamageType.MIND, self:mindCrit(t.getDamage(self, t), nil, wrath.power), {type="mind", true}) -- No Martyr loops
-		else
-			self:project(tg, a.x, a.y, DamageType.MIND, self:mindCrit(t.getDamage(self, t)), {type="mind"}, true) -- No Martyr loops
+		if damage > 0 then
+			if wrath then
+				self:project(tg, wrath.target.x, wrath.target.y, DamageType.MIND, self:mindCrit(damage, nil, wrath.power), nil, true) -- No Martyr loops
+				game.level.map:particleEmitter(wrath.target.x, wrath.target.y, 1, "generic_discharge", {rm=255, rM=255, gm=180, gM=255, bm=0, bM=0, am=35, aM=90})
+			else
+				self:project(tg, a.x, a.y, DamageType.MIND, self:mindCrit(damage), nil, true) -- No Martyr loops
+				game.level.map:particleEmitter(a.x, a.y, 1, "generic_discharge", {rm=255, rM=255, gm=180, gM=255, bm=0, bM=0, am=35, aM=90})
+			end
 		end
 	end,
 	info = function(self, t)
-		local damage = t.getDamage(self, t)
 		local range = self:getTalentRange(t)
-		return ([[Your subconscious now retaliates when you're attacked, inflicting %0.2f mind damage to any creature within a radius of %d when the damage it deals to you results in you gaining at least one Feedback.
-		The damage will scale with your mindpower.]]):format(damDesc(self, DamageType.MIND, damage), range)
+		local damage = t.getDamage(self, t)
+		return ([[Your subconscious now retaliates when you take damage.  If the attacker is within range (%d) you'll inflict mind damage equal to the Feedback gained from the attack or %0.2f, whichever is lower.
+		The damage will scale with your mindpower.]]):format(range, damDesc(self, DamageType.MIND, damage))
 	end,
 }
 
@@ -84,10 +89,10 @@ newTalent{
 	cooldown = 12,
 	tactical = { ATTACKAREA = {MIND = 2}},
 	requires_target = true,
-	proj_speed = 20,
+	proj_speed = 10,
 	range = function(self, t) return 5 + math.min(5, (self:isTalentActive(self.T_MIND_STORM) and self:getTalentLevelRaw(self.T_MIND_STORM)) or 0) end,
 	target = function(self, t)
-		return {type="bolt", range=self:getTalentRange(t), talent=t, friendlyfire=false, display={particle="bolt_void", trail="dust_trail"}}
+		return {type="bolt", range=self:getTalentRange(t), talent=t, friendlyfire=false, display={particle="discharge_bolt", trail="lighttrail"}}
 	end,
 	getDamage = function(self, t) return self:combatTalentMindDamage(t, 20, 140) end,
 	getTargetCount = function(self, t) return math.ceil(self:getTalentLevel(t)) end,
@@ -142,11 +147,13 @@ newTalent{
 	end,
 	activate = function(self, t)
 		local ret = {
-			overcharge = 0
+			overcharge = 0,
+			particles = self:addParticles(Particles.new("ultrashield", 1, {rm=255, rM=255, gm=180, gM=255, bm=0, bM=0, am=35, aM=90, radius=0.2, density=15, life=28, instop=10}))
 		}
 		return ret
 	end,
 	deactivate = function(self, t, p)
+		self:removeParticles(p.particles)
 		return true
 	end,
 	info = function(self, t)
@@ -188,6 +195,7 @@ newTalent{
 		
 		self:setEffect(self.EFF_FOCUSED_WRATH, t.getDuration(self, t), {target=target, power=t.getCritBonus(self, t)/100})
 
+		game.level.map:particleEmitter(self.x, self.y, 1, "generic_charge", {rm=255, rM=255, gm=180, gM=255, bm=0, bM=0, am=35, aM=90})
 		return true
 	end,
 	info = function(self, t)
diff --git a/game/modules/tome/data/talents/psionic/distortion.lua b/game/modules/tome/data/talents/psionic/distortion.lua
index 0906cb9e80456cbc5d05040bb3f3b2a975bfd9f1..94bc626c3f488e7f45a04428c27ebc988e648a04 100644
--- a/game/modules/tome/data/talents/psionic/distortion.lua
+++ b/game/modules/tome/data/talents/psionic/distortion.lua
@@ -17,7 +17,7 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles
+-- Edge TODO: Sounds
 
 local Object = require "mod.class.Object"
 
@@ -32,10 +32,10 @@ newTalent{
 	range = 10,
 	radius = function(self, t) return 1 + math.floor(self:getTalentLevel(t)/3) end,
 	requires_target = true,
-	getDamage = function(self, t) return self:combatTalentMindDamage(t, 10, 100) end,
+	getDamage = function(self, t) return self:combatTalentMindDamage(t, 10, 150) end,
 	getDetonateDamage = function(self, t) return self:combatTalentMindDamage(t, 20, 200) end,
 	target = function(self, t)
-		return {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="bolt_void", trail="dust_trail"}}
+		return {type="bolt", range=self:getTalentRange(t), talent=t, display={trail="distortion_trail"}}
 	end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
@@ -49,7 +49,7 @@ newTalent{
 		local detonate_damage = t.getDetonateDamage(self, t)
 		local radius = self:getTalentRadius(t)
 		return ([[Fire a bolt of distortion that ignores resistance and inflicts %0.2f physical damage.  This damage will distort affected targets, rendering them vulnerable to distortion effects.
-		If the bolt comes in contact with a target that's already distorted a detonation will occur, inflicting %0.2f physical damage in a %d radius.
+		If the bolt comes in contact with a target that's already distorted a detonation will occur, inflicting %0.2f physical damage in a radius of %d.
 		The damage will scale with your mindpower.]]):format(damDesc(self, DamageType.PHYSICAL, damage), damDesc(self, DamageType.PHYSICAL, detonate_damage), radius)
 	end,
 }
@@ -75,7 +75,8 @@ newTalent{
 		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.DISTORTION, {dam=self:mindCrit(t.getDamage(self, t)), knockback=t.getPower(self, t), stun=t.getPower(self, t)}, {type="mind"})
+		self:project(tg, x, y, DamageType.DISTORTION, {dam=self:mindCrit(t.getDamage(self, t)), knockback=t.getPower(self, t), stun=t.getPower(self, t)})
+		game.level.map:particleEmitter(self.x, self.y, tg.radius, "generic_wave", {radius=tg.radius, tx=x-self.x, ty=y-self.y, rm=255, rM=255, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 		return true
 	end,
 	info = function(self, t)
@@ -101,7 +102,7 @@ newTalent{
 	requires_target = true,
 	direct_hit = true,
 	getDamage = function(self, t) return self:combatTalentMindDamage(t, 10, 50) end,
-	getDuration = function(self, t) return 2 + math.ceil(self:getTalentLevel(t)) end,
+	getDuration = function(self, t) return 4 + math.floor(self:getTalentLevel(t)) end,
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), talent=t}
 	end,
@@ -141,7 +142,7 @@ newTalent{
 	psi = 30,
 	tactical = { ATTACK = { PHYSICAL = 2}, DISABLE = 2},
 	range = 10,
-	radius = function(self, t) return 3 end,
+	radius = function(self, t) return math.min(4, 1 + math.ceil(self:getTalentLevel(t)/3)) end,
 	requires_target = true,
 	getDamage = function(self, t) return self:combatTalentMindDamage(t, 10, 50) end,
 	getDuration = function(self, t) return 4 + math.ceil(self:getTalentLevel(t)) end,
@@ -162,7 +163,7 @@ newTalent{
 		local e = Object.new{
 			old_feat = oe,
 			type = oe.type, subtype = oe.subtype,
-			name = "maelstrom", image = oe.image, add_mos = {{image = "terrain/wormhole.png"}},
+			name = "maelstrom", image = oe.image, --add_mos = {{image = "terrain/wormhole.png"}},
 			display = '&', color_r=255, color_g=255, color_b=255, back_color=colors.STEEL_BLUE,
 			always_remember = true,
 			temporary = t.getDuration(self, t),
@@ -206,7 +207,7 @@ newTalent{
 			summoner = self,
 		}
 		
-		e.particles = game.level.map:particleEmitter(x, y, 3, "leavestide", {only_one=true}) -- Edge TODO: Make particles for this
+		e.particles = game.level.map:particleEmitter(x, y, e.radius, "generic_vortex", {radius=e.radius, rm=255, rM=255, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 		game.level:addEntity(e)
 		game.level.map(x, y, Map.TERRAIN, e)
 		game.nicer_tiles:updateAround(game.level, x, y)
@@ -217,8 +218,9 @@ newTalent{
 	info = function(self, t)
 		local duration = t.getDuration(self, t)
 		local damage = t.getDamage(self, t)
-		return ([[Create a powerful maelstorm for %d turns.  Each turn the maelstrom will pull in actors within a radius of 3 and inflict %0.2f physical damage.
+		local radius = self:getTalentRadius(t)
+		return ([[Create a powerful maelstorm for %d turns.  Each turn the maelstrom will pull in actors within a radius of %d and inflict %0.2f physical damage.
 		This damage will distort affected targets, rendering them vulnerable to distortion effects.
-		The damage will scale with your mindpower.]]):format(duration, damDesc(self, DamageType.PHYSICAL, damage))
+		The damage will scale with your mindpower.]]):format(duration, radius, damDesc(self, DamageType.PHYSICAL, damage))
 	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/psionic/dreaming.lua b/game/modules/tome/data/talents/psionic/dreaming.lua
index 21bbb906cb398f2d39a9cd9f098f94fcccb977d4..71e5b4c702b884f3f37b22ee4083293e157f0c79 100644
--- a/game/modules/tome/data/talents/psionic/dreaming.lua
+++ b/game/modules/tome/data/talents/psionic/dreaming.lua
@@ -17,7 +17,7 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles,
+-- Edge TODO: Sounds
 
 newTalent{
 	name = "Sleep",
@@ -64,6 +64,7 @@ newTalent{
 			if target then
 				if target:canBe("sleep") then
 					target:setEffect(target.EFF_SLEEP, t.getDuration(self, t), {src=self, power=power, waking=is_waking, insomnia=t.getInsomniaDuration(self, t), no_ct_effect=true, apply_power=self:combatMindpower()})
+					game.level.map:particleEmitter(target.x, target.y, 1, "generic_charge", {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 				else
 					game.logSeen(self, "%s resists the sleep!", target.name:capitalize())
 				end
@@ -152,7 +153,7 @@ newTalent{
 			end
 		end
 		
-		game.level.map:particleEmitter(self.x, self.y, 1, "teleport")
+		game.level.map:particleEmitter(x, y, 1, "generic_teleport", {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 
 		-- since we're using a precise teleport we'll look for a free grid first
 		local tx, ty = util.findFreeGrid(x, y, 5, true, {[Map.ACTOR]=true})
@@ -162,7 +163,7 @@ newTalent{
 			end
 		end
 
-		game.level.map:particleEmitter(self.x, self.y, 1, "teleport")
+		game.level.map:particleEmitter(self.x, self.y, 1, "generic_teleport", {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 		game:playSoundNear(self, "talents/teleport")
 
 		return true
@@ -194,11 +195,13 @@ newTalent{
 		game:playSoundNear(self, "talents/heal")
 		local ret = {
 			drain = self:addTemporaryValue("psi_regen", -t.getDrain(self, t)),
+			particles = self:addParticles(engine.Particles.new("ultrashield", 1, {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=70, aM=180, radius=0.8, density=60, life=14, instop=20, static=80}))
 		}
 		return ret
 	end,
 	deactivate = function(self, t, p)
 		self:removeTemporaryValue("psi_regen", p.drain)
+		self:removeParticles(p.particles)
 		return true
 	end,
 	info = function(self, t)
diff --git a/game/modules/tome/data/talents/psionic/feedback.lua b/game/modules/tome/data/talents/psionic/feedback.lua
index d6973aaaaadaa7aca47054420d60c7d276e5e3e2..0b47a699b161500b2603ddd29dc49d5b87e5b920 100644
--- a/game/modules/tome/data/talents/psionic/feedback.lua
+++ b/game/modules/tome/data/talents/psionic/feedback.lua
@@ -17,7 +17,7 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles,
+-- Edge TODO: Sounds
 
 newTalent{
 	name = "Biofeedback",
@@ -112,6 +112,7 @@ newTalent{
 				self[inc] then self[inc](self, v) 
 			end
 		end
+		game.level.map:particleEmitter(self.x, self.y, 1, "generic_charge", {rm=255, rM=255, gm=180, gM=255, bm=0, bM=0, am=35, aM=90})
 		return true
 	end,
 	info = function(self, t)
diff --git a/game/modules/tome/data/talents/psionic/mentalism.lua b/game/modules/tome/data/talents/psionic/mentalism.lua
index eb595b4e1bf5109486b09fe250ebc5b6f5e0f087..0f011aec9e75c197749a1c3ef10f87514621e63d 100644
--- a/game/modules/tome/data/talents/psionic/mentalism.lua
+++ b/game/modules/tome/data/talents/psionic/mentalism.lua
@@ -17,7 +17,7 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles
+-- Edge TODO: Sounds
 
 local Map = require "engine.Map"
 
@@ -124,7 +124,6 @@ newTalent{
 		end
 		
 		local m = self:clone{
-			shader = "shadow_simulacrum",
 			no_drops = true,
 			faction = self.faction,
 			summoner = self, summoner_gain_exp=true,
@@ -237,7 +236,10 @@ newTalent{
 		local target = game.level.map(x, y, Map.ACTOR)
 		if not target or target == self then return end
 		
-		target:setEffect(target.EFF_MIND_LINK_TARGET, 10, {power=t.getBonusDamage(self, t), src=self, range=self:getTalentRange(t)})
+		target:setEffect(target.EFF_MIND_LINK_TARGET, 10, {power=t.getBonusDamage(self, t), src=self, range=self:getTalentRange(t)*2})
+		
+		game.level.map:particleEmitter(self.x, self.y, 1, "generic_discharge", {rm=0, rM=0, gm=100, gM=180, bm=180, bM=255, am=35, aM=90})
+		game.level.map:particleEmitter(target.x, target.y, 1, "generic_discharge", {rm=0, rM=0, gm=100, gM=180, bm=180, bM=255, am=35, aM=90})
 		
 		local ret = {
 			target = target,
@@ -257,8 +259,9 @@ newTalent{
 	end,
 	info = function(self, t)
 		local damage = t.getBonusDamage(self, t)
+		local range = self:getTalentRange(t) * 2
 		return ([[Link minds with the target.  While your minds are linked you'll inflict %d%% more mind damage to the target and gain telepathy to it's creature type.
-		Only one mindlink can be maintained at a time and the effect will break if the target dies or goes beyond the talent range.
-		The mind damage bonus will scale with your mindpower.]]):format(damage)
+		Only one mindlink can be maintained at a time and the effect will break if the target dies or goes beyond range (%d)).
+		The mind damage bonus will scale with your mindpower.]]):format(damage, range)
 	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/talents/psionic/nightmare.lua b/game/modules/tome/data/talents/psionic/nightmare.lua
index 62b44b585accf215fe66c881f55ac3e5a3fc9c46..90e92826728c36a6ffbecb3014c73f44b3a9819f 100644
--- a/game/modules/tome/data/talents/psionic/nightmare.lua
+++ b/game/modules/tome/data/talents/psionic/nightmare.lua
@@ -17,7 +17,7 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles,
+-- Edge TODO: Sounds
 
 newTalent{
 	name = "Nightmare",
@@ -69,6 +69,9 @@ newTalent{
 				end
 			end
 		end)
+		
+		game.level.map:particleEmitter(self.x, self.y, tg.radius, "generic_wave", {radius=tg.radius, tx=x-self.x, ty=y-self.y, rm=60, rM=130, gm=20, gM=110, bm=90, bM=130, am=35, aM=90})
+		
 		return true
 	end,
 	info = function(self, t)
@@ -106,6 +109,7 @@ newTalent{
 
 		local m = target:clone{
 			shader = "shadow_simulacrum",
+			shader_args = { color = {0.6, 0.0, 0.3}, base = 0.3, time_factor = 2000 },
 			no_drops = true,
 			faction = self.faction,
 			summoner = self, summoner_gain_exp=true,
@@ -138,6 +142,10 @@ newTalent{
 		m.can_talk = nil
 		m.clone_on_hit = nil
 
+		-- Inner Demon's never flee
+		m.ai_tactic = m.ai_tactic or {}
+		m.ai_tactic.escape = 0
+		
 		-- Remove some talents
 		local tids = {}
 		for tid, _ in pairs(m.talents) do
@@ -166,7 +174,7 @@ newTalent{
 		end
 
 		game.zone:addEntity(game.level, m, "actor", x, y)
-		game.level.map:particleEmitter(x, y, 1, "shadow")
+		game.level.map:particleEmitter(x, y, 1, "generic_teleport", {rm=60, rM=130, gm=20, gM=110, bm=90, bM=130, am=70, aM=180})
 
 		game.logSeen(target, "#F53CBE#%s's Inner Demon manifests!", target.name:capitalize())
 
@@ -230,6 +238,7 @@ newTalent{
 		if target:attr("sleep") then chance = chance * 2 end
 		if target:canBe("fear") then
 			target:setEffect(target.EFF_WAKING_NIGHTMARE, t.getDuration(self, t), {src = self, chance=t.getChance(self, t), dam=self:mindCrit(t.getDamage(self, t)), apply_power=self:combatMindpower()})
+			game.level.map:particleEmitter(target.x, target.y, 1, "generic_charge", {rm=60, rM=130, gm=20, gM=110, bm=90, bM=130, am=70, aM=180})
 		else
 			game.logSeen(target, "%s resists the nightmare!", target.name:capitalize())
 		end
@@ -308,7 +317,7 @@ newTalent{
 		m:forceLevelup(self.level)
 		
 		game.zone:addEntity(game.level, m, "actor", x, y)
-		game.level.map:particleEmitter(x, y, 1, "shadow")
+		game.level.map:particleEmitter(x, y, 1, "generic_teleport", {rm=60, rM=130, gm=20, gM=110, bm=90, bM=130, am=70, aM=180})
 		
 		if game.party:hasMember(self) then
 			game.party:addMember(m, {
@@ -324,11 +333,13 @@ newTalent{
 		game:playSoundNear(self, "talents/heal")
 		local ret = {
 			damage = self:addTemporaryValue("night_terror", t.getDamageBonus(self, t)),
+			particle = self:addParticles(Particles.new("ultrashield", 1, {rm=60, rM=130, gm=20, gM=110, bm=90, bM=130, am=70, aM=180, radius=0.4, density=60, life=14, instop=20})),
 		}
 		return ret
 	end,
 	deactivate = function(self, t, p)
 		self:removeTemporaryValue("night_terror", p.damage)
+		self:removeParticles(p.particle)
 		return true
 	end,
 	info = function(self, t)
diff --git a/game/modules/tome/data/talents/psionic/psionic.lua b/game/modules/tome/data/talents/psionic/psionic.lua
index 0a03f15400522f23396559e2b194beeb14e704db..2c7c858b8701ab0ed7dc64906ece25963ac67558 100644
--- a/game/modules/tome/data/talents/psionic/psionic.lua
+++ b/game/modules/tome/data/talents/psionic/psionic.lua
@@ -236,11 +236,13 @@ function setupThoughtForm(self, m, x, y)
 	m:resolve() m:resolve(nil, true)
 	m:forceLevelup(self.level)
 	game.zone:addEntity(game.level, m, "actor", x, y)
-	game.level.map:particleEmitter(x, y, 1, "summon")
+	game.level.map:particleEmitter(x, y, 1, "generic_teleport", {rm=225, rM=255, gm=225, gM=255, bm=225, bM=255, am=35, aM=90})
 
-	-- Summons never flee
-	m.ai_tactic = m.ai_tactic or {}
-	m.ai_tactic.escape = 0
+	-- Summons never flee...  unless they're bowmen
+	if m.name ~= "thought-forged bowman" then
+		m.ai_tactic = m.ai_tactic or {}
+		m.ai_tactic.escape = 0
+	end
 end
 
 load("/data/talents/psionic/absorption.lua")
diff --git a/game/modules/tome/data/talents/psionic/psychic-assault.lua b/game/modules/tome/data/talents/psionic/psychic-assault.lua
index cd6c9f5c7dc06568fd1943ea04d15fc0e8965492..77720f24a1673a9ddb2d6e3997383dd4a493fb55 100644
--- a/game/modules/tome/data/talents/psionic/psychic-assault.lua
+++ b/game/modules/tome/data/talents/psionic/psychic-assault.lua
@@ -17,7 +17,7 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles
+-- Edge TODO: Sounds
 
 newTalent{
 	name = "Sunder Mind",
@@ -42,7 +42,7 @@ newTalent{
 		if not target then return end
 		
 		local dam =self:mindCrit(t.getDamage(self, t))
-		self:project(tg, x, y, DamageType.MIND, {dam=dam, alwaysHit=true})
+		self:project(tg, x, y, DamageType.MIND, {dam=dam, alwaysHit=true}, {type="mind"})
 		target:setEffect(target.EFF_SUNDER_MIND, 2, {power=dam/10})
 			
 		return true
@@ -146,7 +146,8 @@ newTalent{
 	getDamage = function(self, t) return self:combatTalentMindDamage(t, 20, 200) end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
-		self:project(tg, self.x, self.y, DamageType.MIND, {dam=self:mindCrit(self:combatTalentMindDamage(t, 20, 200)), crossTierChance=100}, {type="mind"})
+		self:project(tg, self.x, self.y, DamageType.MIND, {dam=self:mindCrit(self:combatTalentMindDamage(t, 20, 200)), crossTierChance=100} )
+		game.level.map:particleEmitter(self.x, self.y, self:getTalentRadius(t), "generic_ball", {radius=self:getTalentRadius(t), rm=100, rM=125, gm=100, gM=125, bm=100, bM=125, am=200, aM=255})
 		game:playSoundNear(self, "talents/spell_generic")
 		return true
 	end,
diff --git a/game/modules/tome/data/talents/psionic/slumber.lua b/game/modules/tome/data/talents/psionic/slumber.lua
index bc8ae5ac1dc0a77f38701288771560dc97c1d452..01b29d2851e46bcc0fb6252043c589a94ac906ed 100644
--- a/game/modules/tome/data/talents/psionic/slumber.lua
+++ b/game/modules/tome/data/talents/psionic/slumber.lua
@@ -17,7 +17,7 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles,
+-- Edge TODO: Sounds
 
 newTalent{
 	name = "Slumber",
@@ -51,6 +51,7 @@ newTalent{
 			local t2 = game.level.map(tx, ty, Map.ACTOR)
 			if t2 and target_two ~= target and rng.percent(p.contagious) and t2:canBe("sleep") then
 				t2:setEffect(t2.EFF_SLEEP, math.floor(p.dur/2), {src=self, power=p.power/10, waking=p.waking, insomnia=math.ceil(p.insomnia/2), no_ct_effect=true, apply_power=self:combatMindpower()})
+				game.level.map:particleEmitter(target.x, target.y, 1, "generic_charge", {rm=0, rM=0, gm=100, gM=200, bm=200, bM=255, am=35, aM=90})
 			end
 		end)
 	end,
@@ -77,6 +78,7 @@ newTalent{
 		local power = self:mindCrit(t.getSleepPower(self, t))
 		if target:canBe("sleep") then
 			target:setEffect(target.EFF_SLUMBER, t.getDuration(self, t), {src=self, power=power, waking=is_waking, contagious=is_contagious, insomnia=t.getInsomniaDuration(self, t), no_ct_effect=true, apply_power=self:combatMindpower()})
+			game.level.map:particleEmitter(target.x, target.y, 1, "generic_charge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180})
 		else
 			game.logSeen(self, "%s resists the sleep!", target.name:capitalize())
 		end
@@ -196,7 +198,7 @@ newTalent{
 			local x1, y1 = util.findFreeGrid(4, 6, 20, true, {[Map.ACTOR]=true})
 			if x1 then
 				self:move(x1, y1, true)
-				game.level.map:particleEmitter(x1, y1, 1, "teleport")
+				game.level.map:particleEmitter(x1, y1, 1, "generic_teleport", {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 			end
 			local x2, y2 = util.findFreeGrid(8, 6, 20, true, {[Map.ACTOR]=true})
 			if x2 then
diff --git a/game/modules/tome/data/talents/psionic/solipsism.lua b/game/modules/tome/data/talents/psionic/solipsism.lua
index f15d98f521cb71e6609dd6c8d5296070bd568982..a34826e1292996686b153225244839722bf838e8 100644
--- a/game/modules/tome/data/talents/psionic/solipsism.lua
+++ b/game/modules/tome/data/talents/psionic/solipsism.lua
@@ -18,7 +18,7 @@
 -- darkgod@te4.org
 
 
--- Edge TODO: Sounds, Particles
+-- Edge TODO: Sounds
 
 newTalent{
 	name = "Solipsism",
@@ -30,15 +30,21 @@ newTalent{
 	getConversionRatio = function(self, t) return math.min(self:getTalentLevel(t) * 0.13, 1) end,
 	on_learn = function(self, t)
 		if self:getTalentLevelRaw(t) == 1 then
-			self.solipsism_threshold = (self.solipsism_threshold or 0) + 0.2
-			self:incMaxPsi(50)
+			self:incMaxPsi((self:getWil()-10) * 1)
+			self.max_life = self.max_life - (self:getCon()-10) * 0.5
+			self.inc_resource_multi.psi = (self.inc_resource_multi.psi or 0) + 1
+			self.inc_resource_multi.life = (self.inc_resource_multi.life or 0) - 0.5
 			self.life_rating = math.ceil(self.life_rating/2)
 			self.psi_rating =  self.psi_rating + 10
+			self.solipsism_threshold = (self.solipsism_threshold or 0) + 0.2
 		end
 	end,
 	on_unlearn = function(self, t)
 		if not self:knowTalent(t) then
-			self:incMaxPsi(-50)
+			self:incMaxPsi(-(self:getWil()-10) * 1)
+			self.max_life = self.max_life + (self:getCon()-10) * 0.5
+			self.inc_resource_multi.psi = self.inc_resource_multi.psi - 1
+			self.inc_resource_multi.life = self.inc_resource_multi.life + 0.5
 			self.solipsism_threshold = self.solipsism_threshold - 0.2
 		end
 	end,
@@ -46,7 +52,8 @@ newTalent{
 		local conversion_ratio = t.getConversionRatio(self, t)
 		return ([[You believe that your mind is the center of everything.  Permanently increases the amount of psi you gain per level by 10 and reduces your life rating (affects life at level up) by 50%% (one time only adjustment).
 		You also have learned to overcome damage with your mind alone and convert %d%% of all damage into Psi damage and %d%% of your healing and life regen now recovers Psi instead of life. 
-		The first talent point invested will also increase your max Psi by 50 and your solipsism threshold by 20%%, reducing global speed if your Psi falls below the threshold (currently %d%%).]]):format(conversion_ratio * 100, conversion_ratio * 100, self.solipsism_threshold * 100)
+		The first talent point invested will also increase the amount of Psi you gain from willpower by 1 but reduce the amount of life you gain from constitution by 0.5.
+		The first talent point also increases your solipsism threshold by 20%% (currently %d%%).]]):format(conversion_ratio * 100, conversion_ratio * 100, self.solipsism_threshold * 100)
 	end,
 }
 
@@ -59,20 +66,27 @@ newTalent{
 	getBalanceRatio = function(self, t) return math.min(self:getTalentLevel(t) * 0.13, 1) end,
 	on_learn = function(self, t)
 		if self:getTalentLevelRaw(t) == 1 then
-			self:incMaxPsi(50)
+			self:incMaxPsi((self:getWil()-10) * 1)
+			self.max_life = self.max_life - (self:getCon()-10) * 0.5
+			self.inc_resource_multi.psi = (self.inc_resource_multi.psi or 0) + 1
+			self.inc_resource_multi.life = (self.inc_resource_multi.life or 0) - 0.5
 			self.solipsism_threshold = (self.solipsism_threshold or 0) + 0.1
 		end
 	end,
 	on_unlearn = function(self, t)
 		if not self:knowTalent(t) then
-			self:incMaxPsi(-50)
+			self:incMaxPsi(-(self:getWil()-10) * 1)
+			self.max_life = self.max_life + (self:getCon()-10) * 0.5
+			self.inc_resource_multi.psi = self.inc_resource_multi.psi - 1
+			self.inc_resource_multi.life = self.inc_resource_multi.life + 0.5
 			self.solipsism_threshold = self.solipsism_threshold - 0.1
 		end
 	end,
 	info = function(self, t)
 		local ratio = t.getBalanceRatio(self, t) * 100
 		return ([[You now substitute %d%% of your mental save for %d%% of your physical and spell saves throws (so at 100%% you would effectively use mental save for all saving throw rolls).
-		The first talent point invested will also increase your max Psi by 50 and your solipsism threshold by 10%% (currently %d%%).]]):format(ratio, ratio, self.solipsism_threshold * 100)
+		The first talent point invested will also increase the amount of Psi you gain from willpower by 1 but reduce the amount of life you gain from constitution by 0.5.
+		Learning this talent also increases your solipsism threshold by 10%% (currently %d%%).]]):format(ratio, ratio, self.solipsism_threshold * 100)
 	end,
 }
 
@@ -86,14 +100,20 @@ newTalent{
 	on_learn = function(self, t)
 		self.clarity_threshold = t.getClarityThreshold(self, t)
 		if self:getTalentLevelRaw(t) == 1 then
-			self:incMaxPsi(50)
+			self:incMaxPsi((self:getWil()-10) * 1)
+			self.max_life = self.max_life - (self:getCon()-10) * 0.5
+			self.inc_resource_multi.psi = (self.inc_resource_multi.psi or 0) + 1
+			self.inc_resource_multi.life = (self.inc_resource_multi.life or 0) - 0.5
 			self.solipsism_threshold = (self.solipsism_threshold or 0) + 0.1
 		end
 	end,
 	on_unlearn = function(self, t)
 		if not self:knowTalent(t) then
 			self.clarity_threshold = nil
-			self:incMaxPsi(-50)
+			self:incMaxPsi(-(self:getWil()-10) * 1)
+			self.max_life = self.max_life + (self:getCon()-10) * 0.5
+			self.inc_resource_multi.psi = self.inc_resource_multi.psi - 1
+			self.inc_resource_multi.life = self.inc_resource_multi.life + 0.5
 			self.solipsism_threshold = self.solipsism_threshold - 0.1
 		else
 			self.clarity_threshold = t.getClarityThreshold(self, t)
@@ -102,7 +122,8 @@ newTalent{
 	info = function(self, t)
 		local threshold = t.getClarityThreshold(self, t)
 		return ([[For every percent that your Psi pool exceeds %d%% you gain 1%% global speed (up to a maximum of 50%%).
-		The first talent point invested will also increase your max Psi by 50 and your solipsism threshold by 10%% (currently %d%%).]]):format(threshold * 100, self.solipsism_threshold * 100)
+		The first talent point invested will also increase the amount of Psi you gain from willpower by 1 but reduce the amount of life you gain from constitution by 0.5.
+		The first talent point also increases your solipsism threshold by 10%% (currently %d%%).]]):format(threshold * 100, self.solipsism_threshold * 100)
 	end,
 }
 
@@ -115,21 +136,27 @@ newTalent{
 	getSavePercentage = function(self, t) return math.min(2, self:getTalentLevel(t)/4) end,
 	on_learn = function(self, t)
 		if self:getTalentLevelRaw(t) == 1 then
-			self:incMaxPsi(50)
+			self:incMaxPsi((self:getWil()-10) * 1)
+			self.max_life = self.max_life - (self:getCon()-10) * 0.5
+			self.inc_resource_multi.psi = (self.inc_resource_multi.psi or 0) + 1
+			self.inc_resource_multi.life = (self.inc_resource_multi.life or 0) - 0.5
 			self.solipsism_threshold = (self.solipsism_threshold or 0) + 0.1
 		end
 	end,
 	on_unlearn = function(self, t)
 		if not self:knowTalent(t) then
-			self:incMaxPsi(-50)
+			self:incMaxPsi(-(self:getWil()-10) * 1)
+			self.max_life = self.max_life + (self:getCon()-10) * 0.5
+			self.inc_resource_multi.psi = self.inc_resource_multi.psi - 1
+			self.inc_resource_multi.life = self.inc_resource_multi.life + 0.5
 			self.solipsism_threshold = self.solipsism_threshold - 0.1
 		end
 	end,
 	doDismissalOnHit = function(self, value, src, t)
-		local saving_throw = self:mindCrit(t.getSavePercentage(self, t))
+		local saving_throw = self:mindCrit(self:combatMentalResist(), t.getSavePercentage(self, t))
 		print("[Dismissal] ", self.name:capitalize(), " attempting to ignore ", value, "damage from ", src.name:capitalize(), "using", saving_throw,  "mental save.")
-		if self:checkHit(math.floor(saving_throw), value) then
-			game.logSeen(self, "%s dismisses %s's attack!", self.name:capitalize(), src.name:capitalize())
+		if self:checkHit(saving_throw, value) then
+			game.logSeen(self, "%s dismisses %s's damage!", self.name:capitalize(), src.name:capitalize())
 			return 0
 		else
 			return value
@@ -138,6 +165,7 @@ newTalent{
 	info = function(self, t)
 		local save_percentage = t.getSavePercentage(self, t)
 		return ([[Each time you take damage you roll %d%% of your mental save against it.  If the saving throw succeeds the damage will be reduced to 0.
-		The first talent point invested will also increase your max Psi by 50 and your solipsism threshold by 10%% (currently %d%%).]]):format(save_percentage * 100, self.solipsism_threshold * 100)
+		The first talent point invested will also increase the amount of Psi you gain from willpower by 1 but reduce the amount of life you gain from constitution by 0.5.
+		The first talent point also increases your solipsism threshold by 10%% (currently %d%%).]]):format(save_percentage * 100, self.solipsism_threshold * 100)
 	end,
 }
diff --git a/game/modules/tome/data/talents/psionic/thought-forms.lua b/game/modules/tome/data/talents/psionic/thought-forms.lua
index 700511fef6f478c4261082b1ec3cc33589156508..8b2bfe23a0e3ac9c402f392a16977875d8c5c632 100644
--- a/game/modules/tome/data/talents/psionic/thought-forms.lua
+++ b/game/modules/tome/data/talents/psionic/thought-forms.lua
@@ -17,12 +17,12 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
--- Edge TODO: Sounds, Particles,
+-- Edge TODO: Sounds
 
 -- Thought Forms
 newTalent{
-	name = "Thought-Form: Warrior",
-	short_name = "TF_WARRIOR",
+	name = "Thought-Form: Bowman",
+	short_name = "TF_BOWMAN",
 	type = {"psionic/other", 1},
 	points = 5, 
 	require = psi_wil_req1,
@@ -48,14 +48,16 @@ newTalent{
 			return
 		end
 		
-		-- Do our stat bonuses here so we only roll for crit once		
+		-- Do our stat bonuses here so we only roll for crit once	
 		local stat_bonus = math.floor(self:mindCrit(t.getStatBonus(self, t)))
 	
 		local NPC = require "mod.class.NPC"
 		local m = NPC.new{
-			name = "thought-forged warrior", summoner = self, 
-			desc = [[A thought-forged warrior wielding a massive hammer and clad in heavy armor.  It appears ready for battle.]],
-			body = { INVEN = 10, MAINHAND = 1, BODY = 1, HANDS = 1, FEET = 1},
+			name = "thought-forged bowman", summoner = self,
+			shader = "shadow_simulacrum",
+			shader_args = { color = {0.8, 0.8, 0.8}, base = 0.8, time_factor = 4000 },
+			desc = [[A thought-forged bowman.  It appears ready for battle.]],
+			body = { INVEN = 10, MAINHAND = 1, BODY = 1, QUIVER=1, HANDS = 1, FEET = 1},
 			-- Make a moddable tile
 			resolvers.generic(function(e)
 				if e.summoner.female then
@@ -69,8 +71,8 @@ newTalent{
 			-- Disable our sustain when we die
 			on_die = function(self)
 				game:onTickEnd(function() 
-					if self.summoner:isTalentActive(self.summoner.T_TF_WARRIOR) then
-						self.summoner:forceUseTalent(self.summoner.T_TF_WARRIOR, {ignore_energy=true})
+					if self.summoner:isTalentActive(self.summoner.T_TF_BOWMAN) then
+						self.summoner:forceUseTalent(self.summoner.T_TF_BOWMAN, {ignore_energy=true})
 					end
 					if self.summoner:isTalentActive(self.summoner.T_OVER_MIND) then
 						self.summoner:forceUseTalent(self.summoner.T_OVER_MIND, {ignore_energy=true})
@@ -79,7 +81,7 @@ newTalent{
 			end,
 			-- Keep them on a leash
 			on_act = function(self)
-				local t = self.summoner:getTalentFromId(self.summoner.T_TF_WARRIOR)
+				local t = self.summoner:getTalentFromId(self.summoner.T_TF_BOWMAN)
 				if not game.level:hasEntity(self.summoner) or core.fov.distance(self.x, self.y, self.summoner.x, self.summoner.y) > self.summoner:getTalentRange(t) then
 					local Map = require "engine.Map"
 					local x, y = util.findFreeGrid(self.summoner.x, self.summoner.y, 5, true, {[Map.ACTOR]=true})
@@ -89,39 +91,40 @@ newTalent{
 					-- Clear it's targeting on teleport
 					self.ai_target.actor = nil
 					self:move(x, y, true)
-					game.level.map:particleEmitter(x, y, 1, "summon")
+					game.level.map:particleEmitter(x, y, 1, "generic_teleport", {rm=225, rM=255, gm=225, gM=255, bm=225, bM=255, am=35, aM=90})
 				end
 			end,
-			
+
 			ai = "summoned", ai_real = "tactical",
 			ai_state = { ai_move="move_dmap", talent_in=3, ally_compassion=10 },
-			ai_tactic = resolvers.tactic("melee"),
+			ai_tactic = resolvers.tactic("ranged"),
 			
 			max_life = resolvers.rngavg(100,110),
-			life_rating = 15,
+			life_rating = 12,
 			combat_armor = 0, combat_def = 0,
 			inc_stats = {
-				str = stat_bonus,
-				dex = stat_bonus / 2,
+				str = stat_bonus / 2,
+				dex = stat_bonus,
 				con = stat_bonus / 2,
 			},
 			
 			resolvers.talents{ 
-				[Talents.T_ARMOUR_TRAINING]= 3,
+				[Talents.T_HEAVE]= math.ceil(self.level/10),
 				[Talents.T_WEAPON_COMBAT]= math.ceil(self.level/10),
-				[Talents.T_WEAPONS_MASTERY]= math.ceil(self.level/10),
+				[Talents.T_BOW_MASTERY]= math.ceil(self.level/10),
+				
+				[Talents.T_STEADY_SHOT]= math.ceil(self.level/10),
+				[Talents.T_RAPID_SHOT]= math.ceil(self.level/10),
 				
-				[Talents.T_RUSH]= math.ceil(self.level/10),
-				[Talents.T_DEATH_DANCE]= math.ceil(self.level/10),
-				[Talents.T_BERSERKER]= math.ceil(self.level/10),
 
 				[Talents.T_PSYCHOMETRY]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
 				[Talents.T_BIOFEEDBACK]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
 				[Talents.T_LUCID_DREAMER]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
 			},
 			resolvers.equip{
-				{type="weapon", subtype="greatmaul", autoreq=true, forbid_power_source={arcane=true, technique=true} },
-				{type="armor", subtype="heavy", autoreq=true, forbid_power_source={arcane=true, technique=true} },
+				{type="weapon", subtype="longbow", autoreq=true, forbid_power_source={arcane=true, technique=true} },
+				{type="ammo", subtype="arrow", autoreq=true, forbid_power_source={arcane=true, technique=true} },
+				{type="armor", subtype="light", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 				{type="armor", subtype="hands", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 				{type="armor", subtype="feet", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 			},
@@ -137,25 +140,25 @@ newTalent{
 		}
 		if self:knowTalent(self.T_TF_UNITY) then
 			local t = self:getTalentFromId(self.T_TF_UNITY)
-			ret.power = self:addTemporaryValue("combat_mindpower", t.getOffensePower(self, t))
+			ret.speed = self:addTemporaryValue("combat_mindspeed", t.getSpeedPower(self, t)/100)
 		end
 		return ret
 	end,
 	deactivate = function(self, t, p)
 		p.summon:die(p.summon)
-		if p.power then self:removeTemporaryValue("combat_mindpower", p.power) end
+		if p.speed then self:removeTemporaryValue("combat_mindspeed", p.speed) end
 		return true
 	end,
 	info = function(self, t)
 		local stat = t.getStatBonus(self, t)
-		return ([[Forge a warrior wielding a greatmaul from your thoughts.  The warrior learns weapon mastery, combat accuracy, berserker, death dance, and rush as it levels up and has %d improved strength, %d dexterity, and %d constitution.
-		The stat bonuses will improve with your mindpower.]]):format(stat, stat/2, stat/2)
+		return ([[Forge a bowman clad in leather armor from your thoughts.  The bowman learns heave, bow mastery, combat accuracy, steady shot, and rapid shot as it levels up and has %d improved strength, %d dexterity, and %d constitution.
+		The stat bonuses will improve with your mindpower.]]):format(stat/2, stat, stat/2)
 	end,
 }
 
 newTalent{
-	name = "Thought-Form: Defender",
-	short_name = "TF_DEFENDER",
+	name = "Thought-Form: Warrior",
+	short_name = "TF_WARRIOR",
 	type = {"psionic/other", 1},
 	points = 5, 
 	require = psi_wil_req1,
@@ -181,14 +184,16 @@ newTalent{
 			return
 		end
 		
-		-- Do our stat bonuses here so we only roll for crit once	
+		-- Do our stat bonuses here so we only roll for crit once		
 		local stat_bonus = math.floor(self:mindCrit(t.getStatBonus(self, t)))
 	
 		local NPC = require "mod.class.NPC"
 		local m = NPC.new{
-			name = "thought-forged defender", summoner = self,
-			desc = [[A thought-forged defender clad in massive armor.  It wields a sword and shield and appears ready for battle.]],
-			body = { INVEN = 10, MAINHAND = 1, OFFHAND = 1, BODY = 1, HANDS = 1, FEET = 1},
+			name = "thought-forged warrior", summoner = self, 
+			shader = "shadow_simulacrum",
+			shader_args = { color = {0.8, 0.8, 0.8}, base = 0.8, time_factor = 4000 },
+			desc = [[A thought-forged warrior wielding a massive hammer and clad in heavy armor.  It appears ready for battle.]],
+			body = { INVEN = 10, MAINHAND = 1, BODY = 1, HANDS = 1, FEET = 1},
 			-- Make a moddable tile
 			resolvers.generic(function(e)
 				if e.summoner.female then
@@ -202,8 +207,8 @@ newTalent{
 			-- Disable our sustain when we die
 			on_die = function(self)
 				game:onTickEnd(function() 
-					if self.summoner:isTalentActive(self.summoner.T_TF_DEFENDER) then
-						self.summoner:forceUseTalent(self.summoner.T_TF_DEFENDER, {ignore_energy=true})
+					if self.summoner:isTalentActive(self.summoner.T_TF_WARRIOR) then
+						self.summoner:forceUseTalent(self.summoner.T_TF_WARRIOR, {ignore_energy=true})
 					end
 					if self.summoner:isTalentActive(self.summoner.T_OVER_MIND) then
 						self.summoner:forceUseTalent(self.summoner.T_OVER_MIND, {ignore_energy=true})
@@ -212,7 +217,7 @@ newTalent{
 			end,
 			-- Keep them on a leash
 			on_act = function(self)
-				local t = self.summoner:getTalentFromId(self.summoner.T_TF_DEFENDER)
+				local t = self.summoner:getTalentFromId(self.summoner.T_TF_WARRIOR)
 				if not game.level:hasEntity(self.summoner) or core.fov.distance(self.x, self.y, self.summoner.x, self.summoner.y) > self.summoner:getTalentRange(t) then
 					local Map = require "engine.Map"
 					local x, y = util.findFreeGrid(self.summoner.x, self.summoner.y, 5, true, {[Map.ACTOR]=true})
@@ -222,41 +227,39 @@ newTalent{
 					-- Clear it's targeting on teleport
 					self.ai_target.actor = nil
 					self:move(x, y, true)
-					game.level.map:particleEmitter(x, y, 1, "summon")
+					game.level.map:particleEmitter(x, y, 1, "generic_teleport", {rm=225, rM=255, gm=225, gM=255, bm=225, bM=255, am=35, aM=90})
 				end
-			end,		
+			end,
 			
 			ai = "summoned", ai_real = "tactical",
 			ai_state = { ai_move="move_dmap", talent_in=3, ally_compassion=10 },
-			ai_tactic = resolvers.tactic("tank"),
+			ai_tactic = resolvers.tactic("melee"),
 			
 			max_life = resolvers.rngavg(100,110),
 			life_rating = 15,
 			combat_armor = 0, combat_def = 0,
 			inc_stats = {
-				str = stat_bonus / 2,
+				str = stat_bonus,
 				dex = stat_bonus / 2,
-				con = stat_bonus,
+				con = stat_bonus / 2,
 			},
 			
 			resolvers.talents{ 
-				[Talents.T_ARMOUR_TRAINING]= 3 + math.ceil(self.level/10),
+				[Talents.T_ARMOUR_TRAINING]= 3,
 				[Talents.T_WEAPON_COMBAT]= math.ceil(self.level/10),
 				[Talents.T_WEAPONS_MASTERY]= math.ceil(self.level/10),
 				
-				[Talents.T_SHIELD_PUMMEL]= math.ceil(self.level/10),
-				[Talents.T_SHIELD_WALL]= math.ceil(self.level/10),
-				
+				[Talents.T_RUSH]= math.ceil(self.level/10),
+				[Talents.T_DEATH_DANCE]= math.ceil(self.level/10),
+				[Talents.T_BERSERKER]= math.ceil(self.level/10),
 
 				[Talents.T_PSYCHOMETRY]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
 				[Talents.T_BIOFEEDBACK]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
 				[Talents.T_LUCID_DREAMER]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
-
 			},
 			resolvers.equip{
-				{type="weapon", subtype="longsword", autoreq=true, forbid_power_source={arcane=true, technique=true} },
-				{type="armor", subtype="shield", autoreq=true, forbid_power_source={arcane=true, technique=true} },
-				{type="armor", subtype="massive", autoreq=true, forbid_power_source={arcane=true, technique=true} },
+				{type="weapon", subtype="battleaxe", autoreq=true, forbid_power_source={arcane=true, technique=true} },
+				{type="armor", subtype="heavy", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 				{type="armor", subtype="hands", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 				{type="armor", subtype="feet", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 			},
@@ -272,25 +275,25 @@ newTalent{
 		}
 		if self:knowTalent(self.T_TF_UNITY) then
 			local t = self:getTalentFromId(self.T_TF_UNITY)
-			ret.resist = self:addTemporaryValue("resists", {all= t.getDefensePower(self, t)})
+			ret.power = self:addTemporaryValue("combat_mindpower", t.getOffensePower(self, t))
 		end
 		return ret
 	end,
 	deactivate = function(self, t, p)
 		p.summon:die(p.summon)
-		if p.resist then self:removeTemporaryValue("resists", p.resist) end
+		if p.power then self:removeTemporaryValue("combat_mindpower", p.power) end
 		return true
 	end,
 	info = function(self, t)
 		local stat = t.getStatBonus(self, t)
-		return ([[Forge a defender wielding a sword and shield from your thoughts.  The solider learns armor training, weapon mastery, combat accuracy, shield pummel, and shield wall as it levels up and has %d improved strength, %d dexterity, and %d constitution.
-		The stat bonuses will improve with your mindpower.]]):format(stat/2, stat/2, stat)
+		return ([[Forge a warrior wielding a battle-axe from your thoughts.  The warrior learns weapon mastery, combat accuracy, berserker, death dance, and rush as it levels up and has %d improved strength, %d dexterity, and %d constitution.
+		The stat bonuses will improve with your mindpower.]]):format(stat, stat/2, stat/2)
 	end,
 }
 
 newTalent{
-	name = "Thought-Form: Bowman",
-	short_name = "TF_BOWMAN",
+	name = "Thought-Form: Defender",
+	short_name = "TF_DEFENDER",
 	type = {"psionic/other", 1},
 	points = 5, 
 	require = psi_wil_req1,
@@ -321,9 +324,11 @@ newTalent{
 	
 		local NPC = require "mod.class.NPC"
 		local m = NPC.new{
-			name = "thought-forged bowman", summoner = self,
-			desc = [[A thought-forged bowman.  It appears ready for battle.]],
-			body = { INVEN = 10, MAINHAND = 1, BODY = 1, QUIVER=1, HANDS = 1, FEET = 1},
+			name = "thought-forged defender", summoner = self,
+			shader = "shadow_simulacrum",
+			shader_args = { color = {0.8, 0.8, 0.8}, base = 0.8, time_factor = 4000 },
+			desc = [[A thought-forged defender clad in massive armor.  It wields a sword and shield and appears ready for battle.]],
+			body = { INVEN = 10, MAINHAND = 1, OFFHAND = 1, BODY = 1, HANDS = 1, FEET = 1},
 			-- Make a moddable tile
 			resolvers.generic(function(e)
 				if e.summoner.female then
@@ -337,8 +342,8 @@ newTalent{
 			-- Disable our sustain when we die
 			on_die = function(self)
 				game:onTickEnd(function() 
-					if self.summoner:isTalentActive(self.summoner.T_TF_BOWMAN) then
-						self.summoner:forceUseTalent(self.summoner.T_TF_BOWMAN, {ignore_energy=true})
+					if self.summoner:isTalentActive(self.summoner.T_TF_DEFENDER) then
+						self.summoner:forceUseTalent(self.summoner.T_TF_DEFENDER, {ignore_energy=true})
 					end
 					if self.summoner:isTalentActive(self.summoner.T_OVER_MIND) then
 						self.summoner:forceUseTalent(self.summoner.T_OVER_MIND, {ignore_energy=true})
@@ -347,7 +352,7 @@ newTalent{
 			end,
 			-- Keep them on a leash
 			on_act = function(self)
-				local t = self.summoner:getTalentFromId(self.summoner.T_TF_BOWMAN)
+				local t = self.summoner:getTalentFromId(self.summoner.T_TF_DEFENDER)
 				if not game.level:hasEntity(self.summoner) or core.fov.distance(self.x, self.y, self.summoner.x, self.summoner.y) > self.summoner:getTalentRange(t) then
 					local Map = require "engine.Map"
 					local x, y = util.findFreeGrid(self.summoner.x, self.summoner.y, 5, true, {[Map.ACTOR]=true})
@@ -357,40 +362,41 @@ newTalent{
 					-- Clear it's targeting on teleport
 					self.ai_target.actor = nil
 					self:move(x, y, true)
-					game.level.map:particleEmitter(x, y, 1, "summon")
+					game.level.map:particleEmitter(x, y, 1, "generic_teleport", {rm=225, rM=255, gm=225, gM=255, bm=225, bM=255, am=35, aM=90})
 				end
-			end,
-
+			end,		
+			
 			ai = "summoned", ai_real = "tactical",
 			ai_state = { ai_move="move_dmap", talent_in=3, ally_compassion=10 },
-			ai_tactic = resolvers.tactic("ranged"),
+			ai_tactic = resolvers.tactic("tank"),
 			
 			max_life = resolvers.rngavg(100,110),
-			life_rating = 12,
+			life_rating = 15,
 			combat_armor = 0, combat_def = 0,
 			inc_stats = {
 				str = stat_bonus / 2,
-				dex = stat_bonus,
-				con = stat_bonus / 2,
+				dex = stat_bonus / 2,
+				con = stat_bonus,
 			},
 			
 			resolvers.talents{ 
-				[Talents.T_HEAVE]= math.ceil(self.level/10),
+				[Talents.T_ARMOUR_TRAINING]= 3 + math.ceil(self.level/10),
 				[Talents.T_WEAPON_COMBAT]= math.ceil(self.level/10),
-				[Talents.T_BOW_MASTERY]= math.ceil(self.level/10),
+				[Talents.T_WEAPONS_MASTERY]= math.ceil(self.level/10),
 				
-				[Talents.T_STEADY_SHOT]= math.ceil(self.level/10),
-				[Talents.T_RAPID_SHOT]= math.ceil(self.level/10),
+				[Talents.T_SHIELD_PUMMEL]= math.ceil(self.level/10),
+				[Talents.T_SHIELD_WALL]= math.ceil(self.level/10),
 				
 
 				[Talents.T_PSYCHOMETRY]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
 				[Talents.T_BIOFEEDBACK]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
 				[Talents.T_LUCID_DREAMER]= math.floor(self:getTalentLevel(self.T_TRANSCENDENT_THOUGHT_FORMS)),
+
 			},
 			resolvers.equip{
-				{type="weapon", subtype="longbow", autoreq=true, forbid_power_source={arcane=true, technique=true} },
-				{type="ammo", subtype="arrow", autoreq=true, forbid_power_source={arcane=true, technique=true} },
-				{type="armor", subtype="light", autoreq=true, forbid_power_source={arcane=true, technique=true} },
+				{type="weapon", subtype="longsword", autoreq=true, forbid_power_source={arcane=true, technique=true} },
+				{type="armor", subtype="shield", autoreq=true, forbid_power_source={arcane=true, technique=true} },
+				{type="armor", subtype="massive", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 				{type="armor", subtype="hands", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 				{type="armor", subtype="feet", autoreq=true, forbid_power_source={arcane=true, technique=true} },
 			},
@@ -406,19 +412,19 @@ newTalent{
 		}
 		if self:knowTalent(self.T_TF_UNITY) then
 			local t = self:getTalentFromId(self.T_TF_UNITY)
-			ret.speed = self:addTemporaryValue("combat_mindspeed", t.getSpeedPower(self, t)/100)
+			ret.resist = self:addTemporaryValue("resists", {all= t.getDefensePower(self, t)})
 		end
 		return ret
 	end,
 	deactivate = function(self, t, p)
 		p.summon:die(p.summon)
-		if p.speed then self:removeTemporaryValue("combat_mindspeed", p.speed) end
+		if p.resist then self:removeTemporaryValue("resists", p.resist) end
 		return true
 	end,
 	info = function(self, t)
 		local stat = t.getStatBonus(self, t)
-		return ([[Forge a bowman clad in leather armor from your thoughts.  The bowman learns disengage, bow mastery, combat accuracy, steady shot, and rapid shot as it levels up and has %d improved strength, %d dexterity, and %d constitution.
-		The stat bonuses will improve with your mindpower.]]):format(stat/2, stat, stat/2)
+		return ([[Forge a defender wielding a sword and shield from your thoughts.  The solider learns armor training, weapon mastery, combat accuracy, shield pummel, and shield wall as it levels up and has %d improved strength, %d dexterity, and %d constitution.
+		The stat bonuses will improve with your mindpower.]]):format(stat/2, stat/2, stat)
 	end,
 }
 
@@ -435,32 +441,32 @@ newTalent{
 	end,
 	getStatBonus = function(self, t) return self:combatTalentMindDamage(t, 5, 50) end,
 	on_learn = function(self, t)
-		if self:getTalentLevel(t) >= 1 and not self:knowTalent(self.T_TF_WARRIOR) then
+		if self:getTalentLevel(t) >= 1 and not self:knowTalent(self.T_TF_BOWMAN) then
+			self:learnTalent(self.T_TF_BOWMAN, true)
+		end
+		if self:getTalentLevel(t) >= 3 and not self:knowTalent(self.T_TF_WARRIOR) then
 			self:learnTalent(self.T_TF_WARRIOR, true)
 		end
-		if self:getTalentLevel(t) >= 3 and not self:knowTalent(self.T_TF_DEFENDER) then
+		if self:getTalentLevel(t) >= 5 and not self:knowTalent(self.T_TF_DEFENDER) then
 			self:learnTalent(self.T_TF_DEFENDER, true)
 		end
-		if self:getTalentLevel(t) >= 5 and not self:knowTalent(self.T_TF_BOWMAN) then
-			self:learnTalent(self.T_TF_BOWMAN, true)
-		end
 	end,	
 	on_unlearn = function(self, t)
-		if self:getTalentLevel(t) < 1 and self:knowTalent(self.T_TF_WARRIOR) then
+		if self:getTalentLevel(t) < 1 and self:knowTalent(self.T_TF_BOWMAN) then
+			self:unlearnTalent(self.T_TF_BOWMAN)
+		end
+		if self:getTalentLevel(t) < 3 and self:knowTalent(self.T_TF_WARRIOR) then
 			self:unlearnTalent(self.T_TF_WARRIOR)
 		end
-		if self:getTalentLevel(t) < 3 and self:knowTalent(self.T_TF_DEFENDER) then
+		if self:getTalentLevel(t) < 5 and self:knowTalent(self.T_TF_DEFENDER) then
 			self:unlearnTalent(self.T_TF_DEFENDER)
 		end
-		if self:getTalentLevel(t) < 5 and self:knowTalent(self.T_TF_BOWMAN) then
-			self:unlearnTalent(self.T_TF_BOWMAN)
-		end
 	end,
 	info = function(self, t)
 		local bonus = t.getStatBonus(self, t)
 		local range = self:getTalentRange(t)
 		return([[Forge a guardian from your thoughts alone.  Your guardian's primary stat will be improved by %d and it's two secondary stats by %d.
-		At talent level one you may forge a powerful warrior wielding a two-handed weapon, at talent level 3 you may forge a strong defender using a sword and shield, and at talent level 5 a mighty bowman clad in leather armor.
+		At talent level one you may forge a mighty bowman clad in leather armor, at level three a powerful warrior wielding a two-handed weapon, and at level five a strong defender using a sword and shield, and at talent level 5 
 		Thought forms can only be maintained up to a range of %d and will rematerialize next to you if this range is exceeded.
 		Only one thought-form may be active at a time and the stat bonuses will improve with your mindpower.]]):format(bonus, bonus/2, range)
 	end,
@@ -505,6 +511,7 @@ newTalent{
 		
 		-- Switch on TickEnd so every thing applies correctly
 		game:onTickEnd(function() 
+			game.level.map:particleEmitter(self.x, self.y, 1, "generic_discharge", {rm=225, rM=255, gm=225, gM=255, bm=225, bM=255, am=35, aM=90})
 			game.party:hasMember(target).on_control = function(self)
 				self.summoner.over_mind_ai = self.summoner.ai
 				self.summoner.ai = "none"
@@ -516,6 +523,7 @@ newTalent{
 					self.summoner:forceUseTalent(self.summoner.T_OVER_MIND, {ignore_energy=true})
 				end
 			end
+			game.level.map:particleEmitter(target.x, target.y, 1, "generic_discharge", {rm=225, rM=255, gm=225, gM=255, bm=225, bM=255, am=35, aM=90})
 			game.party:setPlayer(target)
 			self:resetCanSeeCache()
 		end)
@@ -558,15 +566,15 @@ newTalent{
 	points = 5, 
 	require = psi_wil_req4,
 	mode = "passive",
+	getSpeedPower = function(self, t) return self:combatTalentMindDamage(t, 5, 15) end,
 	getOffensePower = function(self, t) return self:combatTalentMindDamage(t, 10, 30) end,
 	getDefensePower = function(self, t) return self:combatTalentMindDamage(t, 5, 15) end,
-	getSpeedPower = function(self, t) return self:combatTalentMindDamage(t, 5, 15) end,
 	info = function(self, t)
 		local offense = t.getOffensePower(self, t)
 		local defense = t.getDefensePower(self, t)
 		local speed = t.getSpeedPower(self, t)
-		return([[You now gain a %d bonus to mind power while Thought-Form: Warrior is active, a %d%% bonus to resist all while Thought-Form: Defender is active, and a %d%% bonus to mind speed while Thought-Form: Bowman is active.
-		At talent level one any Feedback your Thought-Forms gain will be given to you as well, at talent level three your Thought-Forms gain a bonus to all saves equal to your mental save, and at talent level five they gain a bonus to all damage equal to your bonus mind damage.
-		These bonuses scale with your mindpower.]]):format(offense, defense, speed)
+		return([[You now gain a %d%% bonus to mind speed while Thought-Form: Bowman is active, a %d bonus to mind power while Thought-Form: Warrior is active, and a %d%% bonus to resist all while Thought-Form: Defender is active. 
+		At talent level one any Feedback your Thought-Forms gain will be given to you as well, at level three your Thought-Forms gain a bonus to all saves equal to your mental save, and at level five they gain a bonus to all damage equal to your bonus mind damage.
+		These bonuses scale with your mindpower.]]):format(speed, offense, defense, speed)
 	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/timed_effects/mental.lua b/game/modules/tome/data/timed_effects/mental.lua
index 983a819b56b84456205f150537d6b765ed13267c..be3e286dd8c598f12c7a39e907a2da1fbdfa527f 100644
--- a/game/modules/tome/data/timed_effects/mental.lua
+++ b/game/modules/tome/data/timed_effects/mental.lua
@@ -2272,16 +2272,17 @@ newEffect{
 	on_lose = function(self, err) return "#Target#'s regains it's senses.", "-Lobotomized" end,
 	parameters = { power=1, dam=1 },
 	activate = function(self, eff)
-
 		DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.src:mindCrit(eff.dam))
 		eff.power = math.max(eff.power - (self:attr("confusion_immune") or 0) * 100, 10)
 		eff.tmpid = self:addTemporaryValue("confused", eff.power)
 		eff.cid = self:addTemporaryValue("inc_stats", {[Stats.STAT_CUN]=-eff.power/2})
 		if eff.power <= 0 then eff.dur = 0 end
+		eff.particles = self:addParticles(engine.Particles.new("generic_power", 1, {rm=100, rM=125, gm=100, gM=125, bm=100, bM=125, am=200, aM=255}))
 	end,
 	deactivate = function(self, eff)
 		self:removeTemporaryValue("confused", eff.tmpid)
 		self:removeTemporaryValue("inc_stats", eff.cid)
+		self:removeParticles(eff.particles)
 		if self == game.player and self.updateMainShader then self:updateMainShader() end
 	end,
 }
@@ -2325,9 +2326,11 @@ newEffect{
 	parameters = { power=2 },
 	activate = function(self, eff)
 		self.mental_negative_status_effect_immune = eff.power
+		eff.particles = self:addParticles(engine.Particles.new("generic_power", 1, {rm=0, rM=0, gm=100, gM=180, bm=180, bM=255, am=200, aM=255}))
 	end,
 	deactivate = function(self, eff)
 		self.mental_negative_status_effect_immune = nil
+		self:removeParticles(eff.particles)
 	end,
 }
 
@@ -2343,7 +2346,7 @@ newEffect{
 	on_lose = function(self, err) return "The psychic field around #target# crumbles.", "-Resonance Shield" end,
 	activate = function(self, eff)
 		self.resonance_field_absorb = eff.power
-		eff.particle = self:addParticles(Particles.new("damage_shield", 1))
+		eff.particle = self:addParticles(engine.Particles.new("ultrashield", 1, {rm=255, rM=255, gm=180, gM=255, bm=0, bM=0, am=70, aM=180, radius=0.4, density=60, life=14, instop=1, static=100}))
 		eff.sid = self:addTemporaryValue("resonance_field", eff.power)
 	end,
 	deactivate = function(self, eff)
@@ -2383,6 +2386,12 @@ newEffect{
 	parameters = { power = 1 },
 	on_gain = function(self, err) return "#Target# is gaining feedback.", "+Feedback Loop" end,
 	on_lose = function(self, err) return "#Target# is no longer gaining feedback.", "-Feedback Loop" end,
+	activate = function(self, eff)
+		eff.particle = self:addParticles(Particles.new("ultrashield", 1, {rm=255, rM=255, gm=180, gM=255, bm=0, bM=0, am=35, aM=90, radius=0.2, density=15, life=28, instop=40}))
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle)
+	end,
 }
 
 newEffect{
@@ -2422,6 +2431,11 @@ newEffect{
 		end
 		if dream_prison then
 			eff.dur = eff.dur + 1
+			if not eff.particle then
+				eff.particle = self:addParticles(engine.Particles.new("ultrashield", 1, {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=70, aM=180, radius=0.4, density=60, life=14, instop=1, static=100}))
+			end
+		elseif eff.particle then
+			self:removeParticles(eff.particle)
 		end
 	end,
 	activate = function(self, eff)
@@ -2434,6 +2448,10 @@ newEffect{
 		end
 		if not self:attr("sleep") and eff.waking > 0 then
 			DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.src:mindCrit(eff.waking))
+			game.level.map:particleEmitter(self.x, self.y, 1, "generic_discharge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180})
+		end
+		if eff.particle then
+			self:removeParticles(eff.particle)
 		end
 	end,
 }
@@ -2458,10 +2476,16 @@ newEffect{
 		end
 		if dream_prison then
 			eff.dur = eff.dur + 1
+			if not eff.particle then
+				eff.particle = self:addParticles(engine.Particles.new("ultrashield", 1, {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=70, aM=180, radius=0.4, density=60, life=14, instop=1, static=100}))
+			end
 		elseif eff.contagious > 0 and eff.dur > 1 then
 			local t = eff.src:getTalentFromId(eff.src.T_SLUMBER)
 			t.doContagiousSlumber(eff.src, self, eff, t)
 		end
+		if eff.particle and not dream_prison then
+			self:removeParticles(eff.particle)
+		end
 	end,
 	activate = function(self, eff)
 		eff.sid = self:addTemporaryValue("sleep", eff.power)
@@ -2473,6 +2497,10 @@ newEffect{
 		end
 		if not self:attr("sleep") and eff.waking > 0 then
 			DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.src:mindCrit(eff.waking))
+			game.level.map:particleEmitter(self.x, self.y, 1, "generic_discharge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180})
+		end
+		if eff.particle then
+			self:removeParticles(eff.particle)
 		end
 	end,
 }
@@ -2497,6 +2525,9 @@ newEffect{
 		end
 		if dream_prison then
 			eff.dur = eff.dur + 1
+			if not eff.particle then
+				eff.particle = self:addParticles(engine.Particles.new("ultrashield", 1, {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=70, aM=180, radius=0.4, density=60, life=14, instop=1, static=100}))
+			end
 		else
 			-- Store the power for later
 			local real_power = eff.power
@@ -2506,6 +2537,9 @@ newEffect{
 			-- Set the power back to its baseline
 			eff.power = real_power
 		end
+		if eff.particle and not dream_prison then
+			self:removeParticles(eff.particle)
+		end
 	end,
 	activate = function(self, eff)
 		eff.sid = self:addTemporaryValue("sleep", eff.power)
@@ -2517,6 +2551,10 @@ newEffect{
 		end
 		if not self:attr("sleep") and eff.waking > 0 then
 			DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.src:mindCrit(eff.waking))
+			game.level.map:particleEmitter(self.x, self.y, 1, "generic_discharge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180})
+		end
+		if eff.particle then
+			self:removeParticles(eff.particle)
 		end
 	end,
 }
diff --git a/game/modules/tome/data/timed_effects/other.lua b/game/modules/tome/data/timed_effects/other.lua
index 55bc69c3884771e5a302e49095705d2488e15e57..3e5e127155e0e2f748824daf3d8bf834439f72ac 100644
--- a/game/modules/tome/data/timed_effects/other.lua
+++ b/game/modules/tome/data/timed_effects/other.lua
@@ -1604,6 +1604,7 @@ newEffect{
 			-- Create a clone for later spawning
 			local m = require("mod.class.NPC").new(eff.target:clone{
 				shader = "shadow_simulacrum",
+				shader_args = { color = {0.0, 0.4, 0.8}, base = 0.6 },
 				no_drops = true,
 				faction = eff.target.faction,
 				summoner = eff.target, summoner_gain_exp=true,
@@ -1651,7 +1652,7 @@ newEffect{
 			end
 			
 			game.zone:addEntity(game.level, m, "actor", x, y)
-			game.level.map:particleEmitter(x, y, 1, "shadow")
+			game.level.map:particleEmitter(x, y, 1, "generic_teleport", {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 
 			if game.party:hasMember(eff.target) then
 				game.party:addMember(m, {
@@ -1673,7 +1674,7 @@ newEffect{
 		eff.sid = eff.target:addTemporaryValue("time_prison", 1)
 		eff.tid = eff.target:addTemporaryValue("no_timeflow", 1)
 		eff.imid = eff.target:addTemporaryValue("status_effect_immune", 1)
-		eff.particle = eff.target:addParticles(Particles.new("time_prison", 1))
+		eff.particle = eff.target:addParticles(engine.Particles.new("ultrashield", 1, {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=70, aM=180, radius=0.4, density=60, life=14, instop=1, static=100}))
 		eff.target.energy.value = 0
 		-- Make the invader deadly
 		eff.pid = self:addTemporaryValue("inc_damage", {all=eff.power})
@@ -1719,7 +1720,7 @@ newEffect{
 				if not self.dead then
 					self:move(x1, y1, true)
 					self.on_die, self.dream_plane_on_die = self.dream_plane_on_die, nil
-					game.level.map:particleEmitter(x1, y1, 1, "teleport")
+					game.level.map:particleEmitter(x1, y1, 1, "generic_teleport", {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
 				else
 					self.x, self.y = x1, y1
 				end
diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua
index 7eb46714af0fcdb695481d4b0d6a9e72a6540746..c8985fa829b1716e146f7631302164a114eab53e 100644
--- a/game/modules/tome/data/timed_effects/physical.lua
+++ b/game/modules/tome/data/timed_effects/physical.lua
@@ -1835,5 +1835,9 @@ newEffect{
 			game.logSeen(self, "#LIGHT_RED#%s is being ravaged by distortion!", self.name:capitalize())
 			eff.dam = eff.dam * 1.5
 		end
+		eff.particle = self:addParticles(Particles.new("ultrashield", 1, {rm=255, rM=255, gm=180, gM=255, bm=220, bM=255, am=35, aM=90, radius=0.2, density=15, life=28, instop=40}))
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle)
 	end,
 }
diff --git a/game/modules/tome/data/zones/dreamscape-talent/zone.lua b/game/modules/tome/data/zones/dreamscape-talent/zone.lua
index fd6e7db185223a8fe3c329eb2f09510f13ad0a93..7244509c64c0ffc68dd1e0948fe852eccf2cb24c 100644
--- a/game/modules/tome/data/zones/dreamscape-talent/zone.lua
+++ b/game/modules/tome/data/zones/dreamscape-talent/zone.lua
@@ -46,7 +46,7 @@ return {
 		},
 	},
 	post_process = function(level)
-		game.state:makeWeather(level, 6, {max_nb=7, chance=1, dir=120, speed={0.1, 0.9}, alpha={0.2, 0.4}, particle_name="weather/grey_cloud_%02d"})
+		game.state:makeWeather(level, 6, {max_nb=2, chance=1, dir=120, speed={0.1, 0.9}, alpha={0.2, 0.4}, particle_name="weather/grey_cloud_%02d"})
 	end,
 	foreground = function(level, dx, dx, nb_keyframes)
 		local tick = core.game.getTime()
diff --git a/game/modules/tome/dialogs/CharacterSheet.lua b/game/modules/tome/dialogs/CharacterSheet.lua
index 814412ba9d9e2ae56f636f5ca403cdb007f332c7..0bdba23318bb917e311c6181994a484f9ea8442d 100644
--- a/game/modules/tome/dialogs/CharacterSheet.lua
+++ b/game/modules/tome/dialogs/CharacterSheet.lua
@@ -655,7 +655,7 @@ function _M:drawDialog(kind, actor_to_compare)
 		text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatMindCrit() end, "%d%%", "%+.0f%%")
 		self:mouseTooltip(self.TOOLTIP_MIND_CRIT, s:drawColorStringBlended(self.font,  ("Crit. chance: #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
 		text = compare_fields(player, actor_to_compare, function(actor, ...) return actor:combatMindSpeed() end, "%.2f%%", "%+.2f%%", 100)
-		self:mouseTooltip(self.TOOLTIP_SPELL_SPEED, s:drawColorStringBlended(self.font, ("Mind speed : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
+		self:mouseTooltip(self.TOOLTIP_MIND_SPEED, s:drawColorStringBlended(self.font, ("Mind speed : #00ff00#%s"):format(text), w, h, 255, 255, 255, true)) h = h + self.font_h
 
 		h = 0
 		w = self.w * 0.5
diff --git a/game/modules/tome/dialogs/LevelupDialog.lua b/game/modules/tome/dialogs/LevelupDialog.lua
index 4204552fbf433a1ce52ef67d23562e65dfcda059..d6d8fa7b59291fc6c21d31bb3e2845f7a2dec8fe 100644
--- a/game/modules/tome/dialogs/LevelupDialog.lua
+++ b/game/modules/tome/dialogs/LevelupDialog.lua
@@ -672,17 +672,21 @@ function _M:getStatDesc(item)
 
 	text:add({"color", "LIGHT_BLUE"}, "Stat gives:", dc, true)
 	if stat_id == self.actor.STAT_CON then
-		text:add("Max life: ", color, ("%0.2f"):format(diff * 4), dc, true)
+		local multi_life = 4 + (self.actor.inc_resource_multi.life or 0)
+		text:add("Max life: ", color, ("%0.2f"):format(diff * multi_life), dc, true)
 		text:add("Physical save: ", color, ("%0.2f"):format(diff * 0.35), dc, true)
 	elseif stat_id == self.actor.STAT_WIL then
 		if self.actor:knowTalent(self.actor.T_MANA_POOL) then
-			text:add("Max mana: ", color, ("%0.2f"):format(diff * 5), dc, true)
+			local multi_mana = 5 + (self.actor.inc_resource_multi.mana or 0)
+			text:add("Max mana: ", color, ("%0.2f"):format(diff * multi_mana), dc, true)
 		end
 		if self.actor:knowTalent(self.actor.T_STAMINA_POOL) then
-			text:add("Max stamina: ", color, ("%0.2f"):format(diff * 2.5), dc, true)
+			local multi_stamina = 2.5 + (self.actor.inc_resource_multi.stamina or 0)
+			text:add("Max stamina: ", color, ("%0.2f"):format(diff * multi_stamina), dc, true)
 		end
 		if self.actor:knowTalent(self.actor.T_PSI_POOL) then
-			text:add("Max psi: ", color, ("%0.2f"):format(diff * 1), dc, true)
+			local multi_psi = 1 + (self.actor.inc_resource_multi.psi or 0)
+			text:add("Max psi: ", color, ("%0.2f"):format(diff * multi_psi), dc, true)
 		end
 		text:add("Mindpower: ", color, ("%0.2f"):format(diff * 0.7), dc, true)
 		text:add("Mental save: ", color, ("%0.2f"):format(diff * 0.35), dc, true)