From c9bfe87ccbd1c56cb853bae47e08e56d71c51112 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Thu, 9 Aug 2012 22:36:54 +0000
Subject: [PATCH] more

git-svn-id: http://svn.net-core.org/repos/t-engine4@5423 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/modules/tome/class/Actor.lua             |   8 +-
 game/modules/tome/class/interface/Archery.lua |   2 +
 .../tome/data/birth/classes/psionic.lua       |   2 +
 game/modules/tome/data/damage_types.lua       |  48 +++
 .../tome/data/gfx/effects/broken_dream.png    | Bin 0 -> 2635 bytes
 .../tome/data/gfx/particles/dreamhammer.lua   |  45 +++
 .../gfx/shockbolt/object/dream_hammer.png     | Bin 0 -> 3856 bytes
 .../tome/data/gfx/talents/dream_crusher.png   | Bin 0 -> 4048 bytes
 .../tome/data/gfx/talents/dream_hammer.png    | Bin 0 -> 3234 bytes
 .../tome/data/gfx/talents/dreamforge.png      | Bin 0 -> 1701 bytes
 .../tome/data/gfx/talents/forge_armor.png     | Bin 0 -> 3268 bytes
 .../tome/data/gfx/talents/forge_bellows.png   | Bin 0 -> 3738 bytes
 .../tome/data/gfx/talents/forge_echoes.png    | Bin 0 -> 4047 bytes
 .../tome/data/gfx/talents/forge_shield.png    | Bin 0 -> 4402 bytes
 .../tome/data/gfx/talents/hammer_toss.png     | Bin 0 -> 3146 bytes
 .../talents/chronomancy/spacetime-weaving.lua |   2 +-
 .../tome/data/talents/psionic/distortion.lua  |   5 +-
 .../tome/data/talents/psionic/dream-forge.lua | 267 +++++++++++++++++
 .../tome/data/talents/psionic/dream-smith.lua | 276 ++++++++++++++++++
 .../tome/data/talents/psionic/nightmare.lua   |   2 +-
 .../tome/data/talents/psionic/psionic.lua     |   7 +-
 .../tome/data/talents/psionic/solipsism.lua   |   2 +-
 .../data/talents/psionic/thought-forms.lua    |   5 +-
 .../tome/data/timed_effects/mental.lua        |  69 ++++-
 24 files changed, 728 insertions(+), 12 deletions(-)
 create mode 100644 game/modules/tome/data/gfx/effects/broken_dream.png
 create mode 100644 game/modules/tome/data/gfx/particles/dreamhammer.lua
 create mode 100644 game/modules/tome/data/gfx/shockbolt/object/dream_hammer.png
 create mode 100644 game/modules/tome/data/gfx/talents/dream_crusher.png
 create mode 100644 game/modules/tome/data/gfx/talents/dream_hammer.png
 create mode 100644 game/modules/tome/data/gfx/talents/dreamforge.png
 create mode 100644 game/modules/tome/data/gfx/talents/forge_armor.png
 create mode 100644 game/modules/tome/data/gfx/talents/forge_bellows.png
 create mode 100644 game/modules/tome/data/gfx/talents/forge_echoes.png
 create mode 100644 game/modules/tome/data/gfx/talents/forge_shield.png
 create mode 100644 game/modules/tome/data/gfx/talents/hammer_toss.png
 create mode 100644 game/modules/tome/data/talents/psionic/dream-forge.lua
 create mode 100644 game/modules/tome/data/talents/psionic/dream-smith.lua

diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 9e98c806a1..096f55f2a1 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -493,6 +493,12 @@ function _M:actBase()
 				t.doMindStorm(self, t, p)
 			end
 		end
+		
+		if self:isTalentActive(self.T_DREAMFORGE) then
+			local t, p = self:getTalentFromId(self.T_DREAMFORGE), self:isTalentActive(self.T_DREAMFORGE)
+			t.doForgeStrike(self, t, p)
+		end	
+	
 
 		self:triggerHook{"Actor:actBase:Effects"}
 	end
@@ -2937,7 +2943,7 @@ function _M:learnPool(t)
 		self:learnTalent(self.T_PSI_POOL, true)
 		self.resource_pool_refs[self.T_PSI_POOL] = (self.resource_pool_refs[self.T_PSI_POOL] or 0) + 1
 	end
-	if t.type[1]:find("^psionic/feedback") or t.type[1]:find("^psionic/discharge")and not self:knowTalent(self.T_FEEDBACK_POOL) then
+	if t.type[1]:find("^psionic/feedback") or t.type[1]:find("^psionic/discharge") and not self:knowTalent(self.T_FEEDBACK_POOL) then
 		self:learnTalent(self.T_FEEDBACK_POOL, true)
 	end
 	-- If we learn an archery talent, also learn to shoot
diff --git a/game/modules/tome/class/interface/Archery.lua b/game/modules/tome/class/interface/Archery.lua
index 57e60fbc56..621452a0e0 100644
--- a/game/modules/tome/class/interface/Archery.lua
+++ b/game/modules/tome/class/interface/Archery.lua
@@ -361,6 +361,8 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 	if hitted and not target.dead and target:attr("stamina_regen_when_hit") then target:incStamina(target.stamina_regen_when_hit) end
 	if hitted and not target.dead and target:attr("mana_regen_when_hit") then target:incMana(target.mana_regen_when_hit) end
 	if hitted and not target.dead and target:attr("equilibrium_regen_when_hit") then target:incEquilibrium(-target.equilibrium_regen_when_hit) end
+	if hitted and not target.dead and target:attr("psi_regen_when_hit") then target:incPsi(target.psi_regen_when_hit) end
+	if hitted and not target.dead and target:attr("hate_regen_when_hit") then target:incHate(target.hate_regen_when_hit) end
 	
 	-- Resource regen on hit
 	if hitted and self:attr("stamina_regen_on_hit") then self:incStamina(self.stamina_regen_on_hit) end
diff --git a/game/modules/tome/data/birth/classes/psionic.lua b/game/modules/tome/data/birth/classes/psionic.lua
index 0212f663ec..6b6e15aa1c 100644
--- a/game/modules/tome/data/birth/classes/psionic.lua
+++ b/game/modules/tome/data/birth/classes/psionic.lua
@@ -169,6 +169,7 @@ newBirthDescriptor{
 	talents_types = {
 		-- class
 		["psionic/distortion"]={true, 0.3},
+		["psionic/dream-smith"]={true, 0.3},
 		["psionic/psychic-assault"]={true, 0.3},
 		["psionic/slumber"]={true, 0.3},
 		["psionic/solipsism"]={true, 0.3},
@@ -182,6 +183,7 @@ newBirthDescriptor{
 		
 		-- locked trees
 		["psionic/discharge"]={false, 0.3},
+		["psionic/dream-forge"]={false, 0.3},
 		["psionic/nightmare"]={false, 0.3},
 	},
 	talents = {
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index 855058ba67..88edc4e73e 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -56,6 +56,10 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr)
 			local e = target.tempeffect_def[target.EFF_BLOCKING]
 			dam = e.do_block(type, dam, target.tmp[target.EFF_BLOCKING], target, src)
 		end
+		if target.isTalentActive and target:isTalentActive(target.T_FORGE_SHIELD) then
+			local t = target:getTalentFromId(target.T_FORGE_SHIELD)
+			dam = t.doForgeShield(type, dam, t, target, src)
+		end
 
 		-- Increases damage
 		local mind_linked = false
@@ -2138,4 +2142,48 @@ newDamageType{
 			end
 		end
 	end,
+}
+
+-- Mind/Fire damage with lots of parameter options
+newDamageType{
+	name = "dreamforge", type = "DREAMFORGE",
+	projector = function(src, x, y, type, dam, tmp)
+		local target = game.level.map(x, y, Map.ACTOR)
+		if not target then return end
+		local power, dur, dist, do_particles
+		tmp = tmp or {}
+		if _G.type(dam) == "table" then dam, power, dur, dist, do_particles = dam.dam, dam.power, dam.dur, dam.dist, dam.do_particles end
+		if target and not tmp[target] then 
+			if src:checkHit(src:combatMindpower(), target:combatMentalResist(), 0, 95) then
+				DamageType:get(DamageType.MIND).projector(src, x, y, DamageType.MIND, {dam=dam/2, alwaysHit=true})
+				DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam/2)
+				if power and power > 0 then 
+					local silent = true and target:hasEffect(target.EFF_BROKEN_DREAM) or false
+					target:setEffect(target.EFF_BROKEN_DREAM, dur, {power=power}, silent)
+					target:crossTierEffect(target.EFF_BRAINLOCKED, src:combatMindpower())
+				end
+				-- Do knockback
+				if dist then
+					if target:canBe("knockback") then
+						target:knockback(src.x, src.y, dist)
+						target:crossTierEffect(target.EFF_OFFBALANCE, src:combatMindpower())
+						game.logSeen(target, "%s is knocked back!", target.name:capitalize())
+					else
+						game.logSeen(target, "%s resists the forge bellow!", target.name:capitalize())
+					end
+				end
+				if do_particles then
+					if rng.percent(50) then
+						game.level.map:particleEmitter(target.x, target.y, 1, "generic_discharge", {rm=225, rM=255, gm=160, gM=160, bm=0, bM=0, am=35, aM=90})
+					elseif hit then
+						game.level.map:particleEmitter(target.x, target.y, 1, "generic_discharge", {rm=225, rM=255, gm=225, gM=255, bm=255, bM=255, am=35, aM=90})
+					end
+				end
+			else -- Save for half damage
+				DamageType:get(DamageType.MIND).projector(src, x, y, DamageType.MIND, {dam=dam/4, alwaysHit=true})
+				DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam/4)
+				game.logSeen(target, "%s resists the dream forge!", target.name:capitalize())
+			end
+		end
+	end,
 }
\ No newline at end of file
diff --git a/game/modules/tome/data/gfx/effects/broken_dream.png b/game/modules/tome/data/gfx/effects/broken_dream.png
new file mode 100644
index 0000000000000000000000000000000000000000..6572d17912c49fe4276e15650e7d3cf75421fdf8
GIT binary patch
literal 2635
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/particles/dreamhammer.lua b/game/modules/tome/data/gfx/particles/dreamhammer.lua
new file mode 100644
index 0000000000..abc535e905
--- /dev/null
+++ b/game/modules/tome/data/gfx/particles/dreamhammer.lua
@@ -0,0 +1,45 @@
+-- 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
+
+base_size = 64
+local nb = 1
+
+return {
+	system_rotation = 225 + math.deg(math.atan2(ty-sy, tx-sx)), system_rotationv = 0,
+
+	base = 1000,
+
+	angle = { 0, 0 }, anglev = { 0, 0 }, anglea = { 0, 0 },
+
+	life = { 10, 10 },
+	size = { 64, 64 }, sizev = {0, 0}, sizea = {0, 0},
+
+	r = {255, 255}, rv = {0, 0}, ra = {0, 0},
+	g = {255, 255}, gv = {0, 0}, ga = {0, 0},
+	b = {255, 255}, bv = {0, 0}, ba = {0, 0},
+	a = {255, 255}, av = {0, 0}, aa = {0, 0},
+
+},
+ function(self)
+	if nb == 1 then
+		self.ps:emit(1)
+		nb = nb -1
+	end
+end,
+ 1, tile, true
diff --git a/game/modules/tome/data/gfx/shockbolt/object/dream_hammer.png b/game/modules/tome/data/gfx/shockbolt/object/dream_hammer.png
new file mode 100644
index 0000000000000000000000000000000000000000..9ccdd24db274fefd3266cf729cd7658d54dee77b
GIT binary patch
literal 3856
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
S<7SQk0000<MNUMnLSTZ<z+*xH

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/dream_crusher.png b/game/modules/tome/data/gfx/talents/dream_crusher.png
new file mode 100644
index 0000000000000000000000000000000000000000..add18a553e091451f9b0426284993276009e5e57
GIT binary patch
literal 4048
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
C42|Ug

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/dream_hammer.png b/game/modules/tome/data/gfx/talents/dream_hammer.png
new file mode 100644
index 0000000000000000000000000000000000000000..6d9e3f2c187a075350ef06255bef83e05cfdd9ce
GIT binary patch
literal 3234
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
US01Lt1poj507*qoM6N<$g4!_u82|tP

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/dreamforge.png b/game/modules/tome/data/gfx/talents/dreamforge.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c8e1259d52dd00222199b41a3183bd8d44a90d1
GIT binary patch
literal 1701
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/forge_armor.png b/game/modules/tome/data/gfx/talents/forge_armor.png
new file mode 100644
index 0000000000000000000000000000000000000000..d48f3267c71b19d02eafe914b8b842e2aa66a0c6
GIT binary patch
literal 3268
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
Cd>j7&

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/forge_bellows.png b/game/modules/tome/data/gfx/talents/forge_bellows.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac33b3c0a1ad2edd2106f3c3ff7ea4c9041ba1f7
GIT binary patch
literal 3738
zcmV;L4rTF)P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iyn<
z1vfKw@D>vQ01g^SL_t(|+U1*lbQjf`$3OSEKZr5B1jDNdB_WVtgeWhv1O$UkZDXOJ
zVa3-)I4z~yH*2?Dx2qL<R^4@5q}p?~<<NRST7$5lSSYv%E-@f2C<X}OB_`Q`NP=J#
z2nmqcKjzNNoym`gwwR!EPR{)?GxyFs-{<?h-a!ElpW{RLoFB1II&o?aTmxv}5U?58
zS$^pOpgyh%JbV?*Rq?NV2s{G(qWm)mKr9AtWkF6G_c&(3I$%sAR8@V30N9@cnPx&f
zp&jd*_xpOFw1czZf}G&092gWwcn`rE;7A-)UjuS;E^z>+=D_5SxMu)R3j8JxE4Dk3
zn0N^T@Z1I3NRbhGO2j0zg7q1fC;$)Sz-8y5e!OEg&>P5$fH2lD$v%4Y=ol$Tn@+IN
z01$O}$AMEo>Uo^sfD<sF3v99$KL+%)9O8^&G5&m3vu96J$7H~?i0}aWfUGlcMLDFE
z!=wm1JTzbJ0wv{euQ{iH6kxW+f<-&evh6Y<Ev;+E1YnM(JqLIb7*Y=V_XqbZG}qpV
zFdzf?ZVoIehh^5axshl5QVV;p6q1sXI+h721ua*Z7k8jVLBd`*cP`8jPq^!VT;R8s
zumEBx|6vX!nTOq|V{F`c7J#(0Zq%k}Dz#=%>CukEfTF9yV9X&bJVu)i@CLB09DY|0
zFIuQ7;88>QTRfz-<{u?^<iUd<@P8s?Dxvs>ejNvZn=LJ#1QtfJxj}>AY9rLcHgJ1g
z#(2k1%(%WBURMH2m?q&zE)xOKOc!B#!GMkdK%wQ_=Eu4IozCuf8u+6HPM0n&V{ALP
z&#++TIYAj=r(W01pYx&;5QQT`u@bs=?b`kT^tFCJ6DLaDW5(Y_fk_Q}7sp~jMa5Y*
zi{L25R0(27Ny!lqjZ%Um!kY2@+82N^R;c;_sH_ZM&&q-;%<pF-b8k0_cPwAfON7z6
zod9@92}(4#M$BNpVTKandJ!g1zPkMY$h8=}HqL}eRtx3z@^HC4)Cm1gHVc&aj&H;E
zlQf9XRW!YN_44O#GulT4M+v{z(tZGBTk(8L8xC?^<op-2g5UGX;Q$z|YVH>8Uwg`E
zJ3l8t@=Y=RLAm#L70r*PjcgwP23rpBjW`p&Xs$=ualIMq%(z%wua5{?6l4FcyX#X9
zYfy>_7AU)n_7UZ>K!nFd+6RDsR^q?+z3{a@eS+Vmk$J;CI-7BYqXVIorbxMus;a8v
zun5B~M_5(mY9DduC?#kS?!Rm7rw>4H%YKg>317=g34Z@2k{b*);|??K-hIXZ;0iU#
z(&%y}jIbC`RaNcQ%@%7M(L7|`)3ayKPX_?+F)eX!9%jZP=V^)n9Iyo4Alj#OmIz|5
zy`VISD)@I(Q<KX8C7{J;L9!AG3vUGAhqsO*IXU^_1CU_G<8f}zHsjtnwS)JgS_N7w
z73DJk(d18XGmH%zYCwd{%uN5@GZF~znT{jEcdm3_ao)=99KLG;N~wzrfVNWL^F@d#
z04bhnh;Y<ea+{}BL+x=k?L`<kFo*=lJo@`{+`QmsGpD}3p4Ub3^7n83bjsm#an7Zh
z2vAM5yMzDI$BzdZDmx+}yS~oS-v5fwKOq35(YJk@1uhe&PoD(9(}#otCERt_?H3P#
zmIxE<!%JQ2qh`}tx%5?v)2D-()z!z03Ako(t;K-XMCfDri!<WczM|eU8zneOQ`FPF
zZ^eq0Ai|<l{Wmj(Rsb}bF<v7#b{+tf@9i~?6JD}O1={Ry3B0XFNDTp?O(+!BSWHkN
zOtM1eDiO32{_S68TpR#CFk|;NCY^|y%ejE&u~>M?gC+`ie_l9y>#bc}VF8ff-=|r7
z%8de^2_!1*&s$OFp8ttq%ikP;cg@(jjY(1e@c#SS7ckoGJ!<&?M3bK0C+zq<##yxA
zv}t#cLnsYe$ji$EVD;*C{<FUKz1b%CD4zO{AJDmT=f56+!-VU50tep)0G<aIl9R*U
zqrn%<9sBhQ7OGJ;0IpDtT6pK3cdYQ~t~+#y`!Yw59;ML~P2W$^rfuhtt%Rn>@1vlg
z;I9Lq)+%Q+zF;{=D>I7vhf}9c`7t~_7N%vR^8AAWCG@pSr2JIyyN3yZ?-`^kJl1Ge
z*lf#zZWfKwnhX(AQ{5)Si`9)F!v9Pj!>CcCJ~;sUtzu}%c_#Hxt)pk1(bhl-GoZ!S
zqN~vqi%Pq9*M%u2!h0r>+NA?lDJ}G~p1E5o9MegfGG&VE99OLZrEx@9J}cPF%gM?4
zXaMXCvm#D!AQ~a!0Z?H=)-{nTF6I?Ph9Q?(0KNV8+pfdy-rZ<hQE%p#+qr<!BwLYS
zU%lxdDdEfMiKfAN&`+TUC?PE^4S=arr*d@hd}hs>b$$SP^Z?I)>}UusUKhFf5a5WA
zA+5ddR^^7QF%fVsx11XyB*yXF85tQS<_lG3?Sm&JltXl~fIEEnT@xZTBQ3ypdbNZW
zva_>Ip;bkS2*3T(NSvj=VZnk03>-Kx3_w*Cj2~o#JQTdx_{fXyRSG4V>^L2pt;Wv3
z5D8CLSQQ~wL1Z79nSFhM_8Aj6bm(LVxYO3WhK2^iC>_crsx8JeH#Y;&sZ*!WI^Rgq
zteN-I);?g6^+H}ve>u>*w?%W))Xa`!0&BK4fOZA_+LwbOr>`9bm8MBr=a_?fDSz&c
zJs-Nc#)%W5D9~UD+T7f1)-=VISHM|*qpYk9z}2>ujG;BBtvUXx>DCLC*gZh23@;On
z(qWJ6`-jFx4j3BWYB8Xn3g`9BaTsu|(#EL?TefWR*YkS=TBx#~nV6Uu>NWV`+4L5x
zwYV$+CS>*U*<v%H6##a-VV%_&wQH}^6G63>o7<z6AjPJF`v>!Y<mBX#BSUK%;;?79
zNqOHB;pEAarpX%f=PD)adN%;oUss7$i$hnl&QoQs9c!(bXhon96QTfY1-@n?#=7#L
zt^HN&MJp>$(_$P=VVBk{czVYPUo*E&9mc3p>0wPN;mDcR0A!oof0flsNJ>fyrO=x<
zZ;m)kcg=c>8R?>FQko~9d=h{;bLRM_<wYV#1g+wjz{V!`0|&q5<t0QSOur^bF<;Vd
zxVtS5mFw#2*d}f)enbhm$)5IudZ4Z@Ja6dGp}v;?dv8!>^zGX>NQFhSW5<qQP9N7S
z98tVxF=~`3W~}|Q|L-Rz4D(IP5tq4JL>Mz|W@`W{E5q7e3Mf%HqPgFqS+NL86eC33
z_#HVOJmU&8#Ovu<p$ri!BRehm`Gfsd*y`1*18t^X=7vTQmPf!IXCjRf&2t-fnhl#Q
zUJ=dGrAysSn1>$Xa$}Mxp-BmMEP07>g}3`=)+!S$0q!wo@XWhz>Z+75S~OW%?w(!o
zmgBxa-yPYl6#(nj?PjmI+DTT*?+JR|xu&KjbpK5;*E26vVUx;@1?BMk)!Rd+kzq7?
zLTQ#Qb2sVp^71H{alZ+xnfz>68i>%Mga`k!kHpD$Q(Ro!b}IY=@XubQcFf@o(S~Zm
z{2svzE-^Oyz<GN2w;gB+dIVOB>-{+QPd4B@wmiHIGgdT?DE29#v@~eK-+AYqJ}^Zq
zH~HrmFJA0cv7I|p{@9P%BbsmgX$$(6dwKNHM=z`vc(KXd_8xY%@^^8R`70E~@ZoMx
z=#fJ%Gm=F3df}i}i<Xs@@wU|r^|G_Ak?=WU#0XHD4I)%opOq#hC6Q|O5ofL57Mk;e
z+<qX!5BI;%%P+s|pLfi@d_h40>G#bgXWG|UxNzaeD~2j7;VAHPqp3x2o(`Od(yZy?
zo<DHl5U-e$^jC3mg7M==Gf-I$(9nNtgaP+V91J3Sd)4;P`J$pC5MhOcwV$7#Pnrl5
zpWn#5dGq25v}Vm34j(@J$*aL7BHScGR+d|2JYguRMA26i&rfuVjF}bZP@+jtieFC|
z8d_s{nvUDtT)+Fn(0wzNuvCPKii*(r*;(DF7oq5Z@Ye~Im6de+_FP_l_0@~l6#cJe
z*K7Zwt9$9EZ#G()l;-b6^Xr=iQd?WgFAc@Nsf7G|cXRAdcZ{L81Rq2AbCsr~B*-yG
zj~-2T5oXL^7HP4kFiwOa|M_gIm#wX>z4#j=`}UooN(m!HbIX`ynwy*Xc_@=od{cxs
zzM9Q~Dq+789IaW~OS5_UXuc9EW0hZ{mqh6QuQz0Jd(ByQSI9aZxc?6N%rEBHv19GC
zISTNYp=_}TT5En(a)h(WBojusYn8BjurSypF$to`)7rOpJNr{2ENTjTMM6RXom3FB
z?PKm^&rnxa*M8pz04&^gf)=Ieq%`ZtxmCiwUQ%H+t3qY2smiQ2mVeGvXp0v8(O>^t
z-<rnFPb`W1LUxkUZU6v0C~hk%Uo;Qj*q`6OQbUQCQu@NGpwJ0beL;`kQNr`0IeYf3
z>3j)GmaL<r9BqCp+;l@fI++IKJvzp7>#I3Ym_>qizvMv2OtGPZF{VMxd2=r3m3{2l
zvxkm&wD}pv-G=s#2+xXQ=2r$Ytm2G07cDUZx_cd9M+xghI;`*?$pC;&UrOhC?P^tN
z%>u1iRHrFT)i~xHI-+&0aSU^=T)y>VB_<t;0RR&>)Y52$!Pz3Lyi)jg(QcnkY{wV;
zDbf5`q(cjTK@0%s-@iZA!@Hr3?K|4le2dnIL>M3%Vlmc=Q25kJI{I-zpJLV4)-rfk
zBTdHky>KWhn(msuo>G^D@D~h#w~5jHrE*@9NTOqfJVbb03uB*tflKB1*#C1BV8DO@
z%()?*aiU4lLcNZ$QETS^;WfV-`<Vvdvvhp!|M&R+13V#wZ<xy6WB>pF07*qoM6N<$
Ef*3~|O8@`>

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/forge_echoes.png b/game/modules/tome/data/gfx/talents/forge_echoes.png
new file mode 100644
index 0000000000000000000000000000000000000000..a6fdb221643b3795358acf28494570dcfa85c21e
GIT binary patch
literal 4047
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
BZ2ABI

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/forge_shield.png b/game/modules/tome/data/gfx/talents/forge_shield.png
new file mode 100644
index 0000000000000000000000000000000000000000..52e0bd13d8366377d0186a41ad5d9e3bcbe71fbd
GIT binary patch
literal 4402
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/gfx/talents/hammer_toss.png b/game/modules/tome/data/gfx/talents/hammer_toss.png
new file mode 100644
index 0000000000000000000000000000000000000000..73e08ef8ab95ab66682a33524c08a9276f8f0f66
GIT binary patch
literal 3146
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua b/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
index 29eaa632cd..b71b453e2f 100644
--- a/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
+++ b/game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua
@@ -64,7 +64,7 @@ newTalent{
 	info = function(self, t)
 		local range = self:getTalentRange(t)
 		return ([[Teleports you to up to %d tiles away to a targeted location in line of sight.  Additional talent points increase the range.
-		This spell takes no time to cast..]]):format(range)
+		This spell takes no time to cast.]]):format(range)
 	end,
 }
 
diff --git a/game/modules/tome/data/talents/psionic/distortion.lua b/game/modules/tome/data/talents/psionic/distortion.lua
index e11c835d71..e693b315cb 100644
--- a/game/modules/tome/data/talents/psionic/distortion.lua
+++ b/game/modules/tome/data/talents/psionic/distortion.lua
@@ -152,7 +152,6 @@ newTalent{
 	target = function(self, t)
 		return {type="hit", range=self:getTalentRange(t), nolock=true, talent=t}
 	end,
-	tactical = { ATTACKAREA = { PHYSICAL = 2 }, DISABLE = 1 },
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
@@ -166,8 +165,8 @@ 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"}},
-			display = '&', color_r=255, color_g=255, color_b=255, back_color=colors.STEEL_BLUE,
+			name = "maelstrom", image = oe.image,
+			display = oe.display, color=oe.color, back_color=oe.back_color,
 			always_remember = true,
 			temporary = t.getDuration(self, t),
 			is_maelstrom = true,
diff --git a/game/modules/tome/data/talents/psionic/dream-forge.lua b/game/modules/tome/data/talents/psionic/dream-forge.lua
new file mode 100644
index 0000000000..dd68a6e9c1
--- /dev/null
+++ b/game/modules/tome/data/talents/psionic/dream-forge.lua
@@ -0,0 +1,267 @@
+-- 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 Object = require "mod.class.Object"
+
+newTalent{
+	name = "Forge Shield",
+	type = {"psionic/dream-forge", 1},
+	points = 5, 
+	require = psi_wil_high1,
+	cooldown = 24,
+	sustain_psi = 25,
+	mode = "sustained",
+	tactical = { DEFEND = 2, },
+	getPower = function(self, t) return self:combatTalentMindDamage(t, 15, 150) end,
+	doForgeShield = function(type, dam, t, self, src)
+		-- Grab our damage threshold
+		local dam_threshold = self.max_life * 0.08
+		if self:knowTalent(self.T_SOLIPSISM) then
+			local t = self:getTalentFromId(self.T_SOLIPSISM)
+			local ratio = t.getConversionRatio(self, t)
+			local psi_percent =  self:getMaxPsi() * t.getConversionRatio(self, t)
+			dam_threshold = (self.max_life * (1 - ratio) + psi_percent) * 0.08
+		end
+
+		local dur = self:getTalentLevel(t) >= 5 and 2 or 1
+		local blocked
+		local amt = dam
+		local eff = self:hasEffect(self.EFF_FORGE_SHIELD)
+		if not eff and dam > dam_threshold then
+			self:setEffect(self.EFF_FORGE_SHIELD, dur, {power=t.getPower(self, t), number=1, d_types={[type]=true}})
+			amt = util.bound(dam - t.getPower(self, t), 0, dam)
+			blocked = t.getPower(self, t)
+			game.logSeen(self, "#ORANGE#%s forges a dream shield to block the attack!", self.name:capitalize())
+		elseif eff and eff.d_types[type] then
+			amt = util.bound(dam - eff.power, 0, dam)
+			blocked = eff.power
+		elseif eff and dam > dam_threshold * (1 + eff.number) then
+			eff.number = eff.number + 1
+			eff.d_types[type] = true
+			amt = util.bound(dam - eff.power, 0, dam)
+			blocked = eff.power
+			game.logSeen(self, "#ORANGE#%s's dream shield has been strengthened by the attack!", self.name:capitalize())
+		end
+
+		if blocked then
+			print("[Forge Shield] blocked", math.min(blocked, dam), DamageType.dam_def[type].name, "damage")
+		end
+		
+		if amt == 0 and src.life then src:setEffect(src.EFF_COUNTERSTRIKE, 1, {power=t.getPower(self, t), no_ct_effect=true, src=self, nb=1}) end
+		return amt
+	end,
+	activate = function(self, t)
+		game:playSoundNear(self, "talents/spell_generic")
+		local ret ={
+		}
+		if self:knowTalent(self.T_FORGE_ARMOR) then
+			local t = self:getTalentFromId(self.T_FORGE_ARMOR)
+			ret.def = self:addTemporaryValue("combat_def", t.getDefense(self, t))
+			ret.armor = self:addTemporaryValue("combat_armor", t.getArmor(self, t))
+			ret.psi = self:addTemporaryValue("psi_regen_when_hit", t.getPsiRegen(self, t))
+		end
+		return ret
+	end,
+	deactivate = function(self, t, p)
+		if p.def then self:removeTemporaryValue("combat_def", p.def) end
+		if p.armor then self:removeTemporaryValue("combat_armor", p.armor) end
+		if p.psi then self:removeTemporaryValue("psi_regen_when_hit", p.psi) end
+	
+		return true	
+	end,
+	info = function(self, t)
+		local power = t.getPower(self, t)
+		return ([[When an attack would deal 8%% or more of your effective health you forge the Dream Shield to protect yourself, reducing the damage of all attacks of that type by %0.2f for the next turn.
+		You may block multiple damage types at one time but the base damage threshold increases by 8%% per damage type the shield is already blocking.
+		If you block all of an attack's damage, the attacker will be vulnerable to a deadly counterstrike (a normal attack will instead deal 200%% damage) for one turn.
+		At talent level five the block effect will last two turns.
+		This talent scales with your mindpower.]]):format(power)
+	end,
+}
+
+newTalent{
+	name = "Forge Bellows",
+	type = {"psionic/dream-forge", 2},
+	points = 5, 
+	require = psi_wil_high2,
+	cooldown = 24,
+	psi = 30,
+	tactical = { ATTACKAREA = { FIRE = 2, MIND = 2}, ESCAPE = 2, },
+	range = 0,
+	radius = function(self, t) return math.min(10, 3 + math.ceil(self:getTalentLevel(t)/2)) end,
+	requires_target = true,
+	target = function(self, t)
+		return {type="cone", range=self:getTalentRange(t), friendlyfire=false, radius = self:getTalentRadius(t), talent=t}
+	end,
+	getDuration = function(self, t) return 5 + math.floor(self:getTalentLevel(t)) end,
+	getBlastDamage = function(self, t) return self:combatTalentMindDamage(t, 20, 200) end,
+	getForgeDamage = function(self, t) return self:combatTalentMindDamage(t, 0, 25) end,
+	action = function(self, t)
+		local tg = self:getTalentTarget(t)
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+
+		local blast_damage = self:mindCrit(t.getBlastDamage(self, t))
+		local forge_damage = self:mindCrit(t.getForgeDamage(self, t))
+		
+		-- Do our blast first
+		self:project(tg, x, y, DamageType.DREAMFORGE, {dam=blast_damage, dist=math.ceil(tg.radius/2)})
+		
+		-- Now build our Barrier
+		self:project(tg, x, y, function(px, py, tg, self)
+			local oe = game.level.map(px, py, Map.TERRAIN)
+			if rng.percent(50) or not oe or oe.is_forgebarrier or game.level.map:checkAllEntities(px, py, "block_move") then return end
+			
+			local e = Object.new{
+				old_feat = oe,
+				type = oe.type, subtype = oe.subtype,
+				name = "forge barrier", image = "terrain/lava/lava_mountain5.png",
+				display = '#', color=colors.RED, back_color=colors.DARK_GREY,
+				shader = "shadow_simulacrum",
+				shader_args = { color = {0.6, 0.0, 0.0}, base = 0.9, time_factor = 1500 },
+				always_remember = true,
+				can_pass = {pass_wall=1},
+				block_move = true,
+				block_sight = true,
+				temporary = t.getDuration(self, t),
+				is_forgebarrier = true,
+				x = px, y = py,
+				canAct = false,
+				dam = forge_damage,
+				radius = self:getTalentRadius(t),
+				act = function(self)
+					local tg = {type="ball", range=0, friendlyfire=false, radius = 1, talent=t, x=self.x, y=self.y,}
+					self.summoner:project(tg, self.x, self.y, engine.DamageType.DREAMFORGE, self.dam)
+									
+					self:useEnergy()
+					self.temporary = self.temporary - 1
+					if self.temporary <= 0 then
+						game.level.map(self.x, self.y, engine.Map.TERRAIN, self.old_feat)
+						game.level:removeEntity(self)
+						game.level.map:updateMap(self.x, self.y)
+					end
+				end,
+				summoner_gain_exp = true,
+				summoner = self,
+			}
+		
+			game.level:addEntity(e)
+			game.level.map(px, py, Map.TERRAIN, e)
+			game.nicer_tiles:updateAround(game.level, px, py)
+			game.level.map:updateMap(px, py)
+		end)
+		game:playSoundNear(self, "talents/fireflash")
+		return true
+	end,
+	info = function(self, t)
+		local blast_damage = t.getBlastDamage(self, t)
+		local radius = self:getTalentRadius(t)
+		local duration = t.getDuration(self, t)
+		local forge_damage = t.getForgeDamage(self, t)
+		return ([[Release the bellows of the forge upon your surroundings, inflicting %0.2f mind damage, %0.2f burning damage, and knocking back your enemies in a radius %d cone.
+		Affected terrain may be changed (50%% chance) for %d turns into forge walls that block movement and inflict %0.2f mind and %0.2f fire damage on nearby enemies.
+		The damage and knockback chance will scale with your mindpower.]]):
+		format(damDesc(self, DamageType.MIND, blast_damage), damDesc(self, DamageType.FIRE, blast_damage), radius, duration, damDesc(self, DamageType.MIND, forge_damage), damDesc(self, DamageType.FIRE, forge_damage))
+	end,
+}
+
+newTalent{
+	name = "Forge Armor",
+	type = {"psionic/dream-forge", 3},
+	points = 5,
+	require = psi_wil_high3,
+	mode = "passive",
+	getArmor = function(self, t) return self:combatTalentMindDamage(t, 5, 50) end,
+	getDefense = function(self, t) return self:combatTalentMindDamage(t, 5, 25) end,
+	getPsiRegen = function(self, t) return self:combatTalentMindDamage(t, 1, 5) end,
+	info = function(self, t)
+		local armor = t.getArmor(self, t)
+		local defense = t.getDefense(self, t)
+		local psi = t.getPsiRegen(self, t)
+		return([[Your Forge Shield talent now increses your armor by %d, your defense by %d, and gives you %0.2f psi when you're hit by a melee or ranged attack.
+		The bonuses will scale with your mindpower.]]):format(armor, defense, psi)
+	end,
+}
+
+newTalent{
+	name = "Dreamforge",
+	type = {"psionic/dream-forge", 4},
+	points = 5, 
+	require = psi_wil_high4,
+	cooldown = 24,
+	sustain_psi = 50,
+	mode = "sustained",
+	no_sustain_autoreset = true,
+	tactical = { ATTACKAREA = { FIRE = 2, MIND = 2}, DEBUFF = 2, },
+	range = 0,
+	radius = function(self, t) return math.min(5, 1 + math.ceil(self:getTalentLevel(t)/2)) end,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), friendlyfire=false, radius = self:getTalentRadius(t), talent=t}
+	end,
+	getDamage = function(self, t) return math.ceil(self:combatTalentMindDamage(t, 10, 100)) end,
+	getPower = function(self, t) return math.floor(self:combatTalentMindDamage(t, 5, 50)) end,
+	getDuration = function(self, t) return 1 + math.floor(self:getTalentLevel(t)/2) end,
+	doForgeStrike = function(self, t, p)
+		-- If we moved reset the forge
+		if self.x ~= p.x or self.y ~= p.y or p.new then
+			p.x = self.x; p.y=self.y; p.radius=0; p.damage=0; p.power=0; p.new = nil;
+		-- Otherwise we strike the forge
+		elseif not self.resting then
+			local max_radius = self:getTalentRadius(t)
+			local max_damage = t.getDamage(self, t)
+			local power = t.getPower(self, t)
+			local dur = 0
+			p.radius = math.min(p.radius + 1, max_radius)
+
+			if p.damage < max_damage then
+				p.radius = math.min(p.radius + 1, max_radius)
+				p.damage = math.min(max_damage/4 + p.damage, max_damage)
+				game.logSeen(self, "#GOLD#%s strikes the dreamforge!", self.name:capitalize())
+			elseif p.power == 0 then
+				p.power = power
+				dur = t.getDuration(self, t)
+				game.logSeen(self, "#GOLD#%s begins breaking dreams!", self.name:capitalize())
+				game:playSoundNear(self, "talents/lightning_loud")
+			end
+			local tg = {type="ball", range=self:getTalentRange(t), friendlyfire=false, radius=p.radius, talent=t}
+			self:project(tg, self.x, self.y, engine.DamageType.DREAMFORGE, {dam=self:combatMindCrit(p.damage), power=p.power, dur=dur, do_particles=true })
+		end
+	end,
+	activate = function(self, t)
+		local ret ={
+			x = self.x, y=self.y, radius=0, damage=0, power=0, new = true,
+		}
+		game:playSoundNear(self, "talents/devouringflame")
+		return ret
+	end,
+	deactivate = function(self, t, p)
+		return true	
+	end,
+	info = function(self, t)
+		local radius = self:getTalentRadius(t)
+		local damage = t.getDamage(self, t)
+		local power = t.getPower(self, t)
+		local duration = t.getDuration(self, t)
+		return ([[The pounding forge of thought in your mind is released upon your surroundings.  Each turn that you remain stationary you'll strike the dreamforge, inflicting mind and burning damage on enemies around you.
+		The effect will build over five turns, until it reaches a maximum radius of %d, maximum mind damage of %0.2f, and maximum burning damage of %0.2f.
+		At this point you'll begin breaking the dreams of enemies who hear the forge, reducing their mental save by %d and giving them a %d%% chance of spell failure due too the tremendous echo in their minds for %d turns.
+		The damage and dream breaking effect will scale with your mindpower.]]):
+		format(radius, damDesc(self, DamageType.MIND, damage), damDesc(self, DamageType.FIRE, damage), power, power, duration)
+	end,
+}
diff --git a/game/modules/tome/data/talents/psionic/dream-smith.lua b/game/modules/tome/data/talents/psionic/dream-smith.lua
new file mode 100644
index 0000000000..03ad7e0d5d
--- /dev/null
+++ b/game/modules/tome/data/talents/psionic/dream-smith.lua
@@ -0,0 +1,276 @@
+-- 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
+
+-- Dream-Forge Hammer
+function useDreamHammer(self)
+	local combat = {
+		talented = "dream",
+		sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2},
+
+		wil_attack = true,
+		damrange = 1.5,
+		physspeed = 1, 
+		dam = 16,
+		apr = 0,
+		atk = 0,
+		physcrit = 0,
+		dammod = {wil=1.2},
+		melee_project = {},
+	}
+	if self:knowTalent(self.T_DREAM_HAMMER) then
+		local t = self:getTalentFromId(self.T_DREAM_HAMMER)
+		combat.dam = 16 + t.getBaseDamage(self, t)
+		combat.apr = 0 + t.getBaseApr(self, t)
+		combat.physcrit = 0 + t.getBaseCrit(self, t)
+		combat.atk = 0 + t.getBaseAtk(self, t)
+	end
+	if self:knowTalent(self.T_HAMMER_TOSS) then
+		local t = self:getTalentFromId(self.T_HAMMER_TOSS)
+		combat.atk = t.getAttackTotal(self, t)
+	end
+	if self:knowTalent(self.T_FORGE_ECHOES) then
+		local t = self:getTalentFromId(self.T_FORGE_ECHOES)
+		combat.melee_project = { [engine.DamageType.DREAMFORGE] = t.getProject(self, t) }
+	end
+	return combat
+end
+
+newTalent{
+	name = "Dream Smith's Hammer",
+	short_name = "DREAM_HAMMER",
+	type = {"psionic/dream-smith", 1},
+	points = 5, 
+	require = psi_wil_req1,
+	cooldown = 6,
+	psi = 5,
+	requires_target = true,
+	tactical = { ATTACK = { weapon = 2 } },
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.4, 2.1) end,
+	getBaseDamage = function(self, t) return self:combatTalentMindDamage(t, 0, 60) end,
+	getBaseAtk = function(self, t) return self:combatTalentMindDamage(t, 0, 20) end,
+	getBaseApr = function(self, t) return self:combatTalentMindDamage(t, 0, 20) end,
+	getBaseCrit = function(self, t) return self:combatTalentMindDamage(t, 0, 20) end,
+	action = function(self, t)
+		local tg = {type="hit", range=self:getTalentRange(t)}
+		local x, y, target = self:getTarget(tg)
+		if not x or not y or not target then return nil end
+		if core.fov.distance(self.x, self.y, x, y) > 1 then return nil end
+		local speed, hit = self:attackTargetWith(target, useDreamHammer(self), nil, t.getDamage(self, t))
+		game.level.map:particleEmitter(target.x, target.y, 1, "dreamhammer", {tile="shockbolt/object/dream_hammer", tx=target.x, ty=target.y, sx=self.x, sy=self.y})
+		
+		-- Reset Dream Smith talents
+		if hit then
+			for tid, cd in pairs(self.talents_cd) do
+				local tt = self:getTalentFromId(tid)
+				if tt.type[1]=="psionic/dream-smith" then
+					self.talents_cd[tid] = 0
+				end
+			end
+			if rng.percent(50) then
+				game.level.map:particleEmitter(self.x, self.y, 1, "generic_charge", {rm=225, rM=255, gm=0, gM=0, bm=0, bM=0, am=35, aM=90})
+			elseif hit then
+				game.level.map:particleEmitter(self.x, self.y, 1, "generic_charge", {rm=225, rM=255, gm=225, gM=255, bm=0, bM=0, am=35, aM=90})
+			end
+			game:playSoundNear(self, "talents/heal")
+		end
+
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		local weapon_damage = useDreamHammer(self).dam
+		local weapon_range = useDreamHammer(self).dam * useDreamHammer(self).damrange
+		local weapon_atk = useDreamHammer(self).atk
+		local weapon_apr = useDreamHammer(self).apr
+		local weapon_crit = useDreamHammer(self).physcrit
+		return ([[Smith a hammer from the dream forge and strike a nearby foe, inflicting %d%% weapon damage.  If the attack hits it will bring all Dream Smith talents off cooldown.
+		The base power, accuracy, armour penetration, and critical strike chance of the weapon will scale with your mindpower.
+
+		Current Dream Hammer Stats
+		Base Power: %0.2f - %0.2f
+		Uses Stats: 120%% Wil
+		Damage Type: Physical
+		Accuracy is based on willpower for this weapon.
+		Accuracy Bonus: +%d
+		Armour Penetration: +%d
+		Physical Crit. Chance: +%d]]):format(damage * 100, weapon_damage, weapon_range, weapon_atk, weapon_apr, weapon_crit)
+	end,
+}
+
+newTalent{
+	name = "Hammer Toss",
+	type = {"psionic/dream-smith", 2},
+	points = 5, 
+	require = psi_wil_req2,
+	cooldown = 8,
+	psi = 10,
+	tactical = { ATTACKAREA = { weapon = 2 } },
+	range = function(self, t) return 5 + self:getTalentLevelRaw(t) end,
+	requires_target = true,
+	proj_speed = 10,
+	target = function(self, t)
+		return {type="beam", range=self:getTalentRange(t), selffire=false, talent=t, display={display='', particle="arrow", particle_args={tile="shockbolt/object/dream_hammer"}, trail="firetrail"}}
+	end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	getAttack = function(self, t) return self:getTalentLevel(t) * 10 end, -- Used for the talent display
+	getAttackTotal = function(self, t)
+		local base_atk = 0
+		if self:knowTalent(self.T_DREAM_HAMMER) then
+			local t = self:getTalentFromId(self.T_DREAM_HAMMER)
+			base_atk = 0 + t.getBaseAtk(self, t)
+		end
+		return base_atk + t.getAttack(self, t)
+	end,
+	getDreamHammer = function(self, t) return useDreamHammer(self) end, -- To prevent upvalue issues
+	action = function(self, t)
+		local tg = self:getTalentTarget(t)
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		local _ _, x, y = self:canProject(tg, x, y)
+		
+		print("[Dream Hammer Throw] Projection from", self.x, self.y, "to", x, y)
+		self:projectile(tg, x, y, function(px, py, tg, self)
+			local tmp_target = game.level.map(px, py, engine.Map.ACTOR)
+			if tmp_target and tmp_target ~= self then
+				local t = self:getTalentFromId(self.T_HAMMER_TOSS)
+				self:attackTargetWith(tmp_target, t.getDreamHammer(self, t), nil, t.getDamage(self, t))
+			end
+			if x == px and y == py and self and self.x and self.y then
+				print("[Dream Hammer Return] Projection from", x, y, "to", self.x, self.y)
+				local tgr = tg
+				tgr.x, tgr.y = px, py
+				self:projectile(tgr, self.x, self.y, function(px, py, tgr, self)
+					local tmp_target = game.level.map(px, py, engine.Map.ACTOR)
+					local t = self:getTalentFromId(self.T_HAMMER_TOSS)
+					if tmp_target and tmp_target ~= self then
+						self:attackTargetWith(tmp_target, t.getDreamHammer(self, t), nil, t.getDamage(self, t))
+					end
+				end)
+			end
+		end)
+		
+		game:playSoundNear(self, "talents/warp")
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		local attack_bonus = t.getAttack(self, t)
+		return ([[Throw your Dream Hammer at a distant target, inflicting %d%% weapon damage on all creatures between you and it.  After reaching it's destination the Dream Hammer will return, potentially hitting creatures a second time.
+		Learning this talent increases the accuracy of your Dream Hammer by %d.]]):format(damage * 100, attack_bonus)
+	end,
+}
+
+newTalent{
+	name = "Dream Crusher",
+	type = {"psionic/dream-smith", 3},
+	points = 5, 
+	require = psi_wil_req3,
+	cooldown = 12,
+	psi = 10,
+	requires_target = true,
+	tactical = { ATTACK = { weapon = 2 }, DISABLE = { stun = 2 } },
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	getMasteryDamage = function(self, t) return self:getTalentLevel(t) * 10 end,
+	getPercentInc = function(self, t) return math.sqrt(self:getTalentLevel(t) / 5) / 2 end,
+	getStun = function(self, t) return 2 + math.floor(self:getTalentLevel(t)) end,
+	action = function(self, t)
+		local tg = {type="hit", range=self:getTalentRange(t)}
+		local x, y, target = self:getTarget(tg)
+		if not x or not y or not target then return nil end
+		if core.fov.distance(self.x, self.y, x, y) > 1 then return nil end
+		local speed, hit = self:attackTargetWith(target, useDreamHammer(self), nil, t.getDamage(self, t))
+		game.level.map:particleEmitter(target.x, target.y, 1, "dreamhammer", {tile="shockbolt/object/dream_hammer", tx=target.x, ty=target.y, sx=self.x, sy=self.y})
+		
+		-- Try to stun !
+		if hit then
+			if target:canBe("stun") then
+				target:setEffect(target.EFF_STUNNED, t.getStun(self, t), {apply_power=self:combatMindpower()})
+			else
+				game.logSeen(target, "%s resists the stunning blow!", target.name:capitalize())
+			end
+			if rng.percent(50) then
+				game.level.map:particleEmitter(target.x, target.y, 1, "generic_discharge", {rm=225, rM=255, gm=0, gM=0, bm=0, bM=0, am=35, aM=90})
+			elseif hit then
+				game.level.map:particleEmitter(target.x, target.y, 1, "generic_discharge", {rm=225, rM=255, gm=225, gM=255, bm=0, bM=0, am=35, aM=90})
+			end
+			game:playSoundNear(self, "talents/lightning_loud")
+		end
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		local power = t.getMasteryDamage(self, t)
+		local percent = t.getPercentInc(self, t)
+		local stun = t.getStun(self, t)		
+		return ([[Crush your enemy with your Dream Hammer, inflicting %d%% of weapon damage.  If the attack hits, the target is stunned for %d turns.
+		Stun chance improves with your mindpower.  Learning this talent increases your Physical Power for Dream Hammer damage calculations by %d and all damage with Dream Hammer attacks by %d%%.
+		]]):format(damage * 100, stun, power, percent * 100)
+	end,
+}
+
+newTalent{
+	name = "Forge Echoes",
+	type = {"psionic/dream-smith", 4},
+	points = 5, 
+	require = psi_wil_req4,
+	cooldown = 24,
+	psi = 20,
+	tactical = { ATTACKAREA = { weapon = 3 } },
+	radius = function(self, t) return 1 + math.floor(self:getTalentLevel(t)/2) end,
+	requires_target = true,
+	target = function(self, t)
+		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false }
+	end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.5) end,
+	getProject = function(self, t) return self:combatTalentMindDamage(t, 10, 50) end,
+	action = function(self, t)
+		local tg = {type="hit", range=self:getTalentRange(t)}
+		local x, y, target = self:getTarget(tg)
+		if not x or not y or not target then return nil end
+		if core.fov.distance(self.x, self.y, x, y) > 1 then return nil end
+		local speed, hit = self:attackTargetWith(target, useDreamHammer(self), nil, t.getDamage(self, t))
+		game.level.map:particleEmitter(target.x, target.y, 1, "dreamhammer", {tile="shockbolt/object/dream_hammer", tx=target.x, ty=target.y, sx=self.x, sy=self.y})
+		
+		-- Forge Echoe
+		if hit then
+			local tg = self:getTalentTarget(t)
+			self:project(tg, target.x, target.y, function(px, py, tg, self)
+				local tmp_target = game.level.map(px, py, Map.ACTOR)
+				if tmp_target and tmp_target ~= self and tmp_target ~= target then
+					local hit = self:attackTargetWith(tmp_target, useDreamHammer(self), nil, t.getDamage(self, t))
+					if hit and rng.percent(50) then
+						game.level.map:particleEmitter(tmp_target.x, tmp_target.y, 1, "generic_discharge", {rm=225, rM=255, gm=0, gM=0, bm=0, bM=0, am=35, aM=90})
+					elseif hit then
+						game.level.map:particleEmitter(tmp_target.x, tmp_target.y, 1, "generic_discharge", {rm=225, rM=255, gm=225, gM=255, bm=0, bM=0, am=35, aM=90})
+					end
+				end
+			end)
+			game:playSoundNear(self, "talents/echo")
+		end
+		return true
+	end,
+	info = function(self, t)
+		local damage = t.getDamage(self, t)
+		local radius = self:getTalentRadius(t)
+		local project = t.getProject(self, t)
+		return ([[Strike the target with a mighty blow from the forge, inflicting %d%% weapon damage.  If the attack hits the echo of the attack will lash out at all enemies in a %d radius.
+		Learning this talent adds %0.2f mind damage and %0.2f burning damage to your Dream Hammer strikes.
+		The mind and fire damage will scale with your mindpower.]]):format(damage * 100, radius, damDesc(self, DamageType.MIND, project), damDesc(self, DamageType.FIRE, project))
+	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 7f62378656..62212ba64c 100644
--- a/game/modules/tome/data/talents/psionic/nightmare.lua
+++ b/game/modules/tome/data/talents/psionic/nightmare.lua
@@ -107,7 +107,7 @@ newTalent{
 
 		local m = target:clone{
 			shader = "shadow_simulacrum",
-			shader_args = { color = {0.6, 0.0, 0.3}, base = 0.3, time_factor = 2000 },
+			shader_args = { color = {0.6, 0.0, 0.3}, base = 0.6, time_factor = 1500 },
 			no_drops = true,
 			faction = self.faction,
 			summoner = self, summoner_gain_exp=true,
diff --git a/game/modules/tome/data/talents/psionic/psionic.lua b/game/modules/tome/data/talents/psionic/psionic.lua
index 2dc38987f8..f9ea48e1ae 100644
--- a/game/modules/tome/data/talents/psionic/psionic.lua
+++ b/game/modules/tome/data/talents/psionic/psionic.lua
@@ -34,10 +34,11 @@ newTalentType{ allow_random=true, type="psionic/psi-archery", name = "psi-archer
 newTalentType{ allow_random=true, type="psionic/greater-psi-fighting", name = "greater psi-fighting", description = "Elevate psi-fighting prowess to epic levels." }
 newTalentType{ allow_random=true, type="psionic/brainstorm", name = "brainstorm", description = "Focus your telekinetic powers in ways undreamed of by most mindslayers." }
 
--- Secret Project...
 -- Solipsist Talent Trees
 newTalentType{ allow_random=true, type="psionic/discharge", name = "discharge", description = "Project feedback on the world around you." }
 newTalentType{ allow_random=true, type="psionic/distortion", name = "distortion", description = "Distort reality with your mental energy." }
+newTalentType{ allow_random=true, type="psionic/dream-forge", name = "Dream Forge", description = "Master the dream forge to create powerful armor and effects." }
+newTalentType{ allow_random=true, type="psionic/dream-smith", name = "Dream Smith", description = "Call the dream-forge hammer to smite your foes." }
 newTalentType{ allow_random=true, type="psionic/nightmare", name = "nightmare", description = "Manifest your enemies nightmares." }
 newTalentType{ allow_random=true, type="psionic/psychic-assault", name = "Psychic Assault", description = "Directly attack your opponents minds." }
 newTalentType{ allow_random=true, type="psionic/slumber", name = "slumber", description = "Force enemies into a deep sleep." }
@@ -261,6 +262,8 @@ load("/data/talents/psionic/grip.lua")
 -- Solipsist
 load("/data/talents/psionic/discharge.lua")
 load("/data/talents/psionic/distortion.lua")
+load("/data/talents/psionic/dream-forge.lua")
+load("/data/talents/psionic/dream-smith.lua")
 load("/data/talents/psionic/dreaming.lua")
 load("/data/talents/psionic/mentalism.lua")
 load("/data/talents/psionic/feedback.lua")
@@ -269,7 +272,7 @@ load("/data/talents/psionic/psychic-assault.lua")
 load("/data/talents/psionic/slumber.lua")
 load("/data/talents/psionic/solipsism.lua")
 load("/data/talents/psionic/thought-forms.lua")
-load("/data/talents/psionic/trance.lua")
+--load("/data/talents/psionic/trance.lua")
 
 
 load("/data/talents/psionic/possession.lua")
diff --git a/game/modules/tome/data/talents/psionic/solipsism.lua b/game/modules/tome/data/talents/psionic/solipsism.lua
index 19faccb98b..ff332a191b 100644
--- a/game/modules/tome/data/talents/psionic/solipsism.lua
+++ b/game/modules/tome/data/talents/psionic/solipsism.lua
@@ -56,7 +56,7 @@ newTalent{
 		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 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)
+		The first talent point also increases your solipsism threshold by 20%% (currently %d%%), reducing your global speed by 1%% for each percentage your current Psi falls below this threshold.]]):format(conversion_ratio * 100, conversion_ratio * 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 24d8fdc0ea..6473a17d3c 100644
--- a/game/modules/tome/data/talents/psionic/thought-forms.lua
+++ b/game/modules/tome/data/talents/psionic/thought-forms.lua
@@ -103,6 +103,7 @@ newTalent{
 			max_life = resolvers.rngavg(100,110),
 			life_rating = 12,
 			combat_armor = 0, combat_def = 0,
+			stats = { mag=self:getMag(), wil=self:getWil(), cun=self:getCun()},
 			inc_stats = {
 				str = stat_bonus / 2,
 				dex = stat_bonus,
@@ -244,6 +245,7 @@ newTalent{
 			max_life = resolvers.rngavg(100,110),
 			life_rating = 15,
 			combat_armor = 0, combat_def = 0,
+			stats = { mag=self:getMag(), wil=self:getWil(), cun=self:getCun()},
 			inc_stats = {
 				str = stat_bonus,
 				dex = stat_bonus / 2,
@@ -384,6 +386,7 @@ newTalent{
 			max_life = resolvers.rngavg(100,110),
 			life_rating = 15,
 			combat_armor = 0, combat_def = 0,
+			stats = { mag=self:getMag(), wil=self:getWil(), cun=self:getCun()},
 			inc_stats = {
 				str = stat_bonus / 2,
 				dex = stat_bonus / 2,
@@ -478,7 +481,7 @@ newTalent{
 	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.
+		return([[Forge a guardian from your thoughts alone.  Your guardian's primary stat will be improved by %d, it's two secondary stats by %d, and it will have magic, cunning, and willpower equal to your own.
 		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.
 		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)
diff --git a/game/modules/tome/data/timed_effects/mental.lua b/game/modules/tome/data/timed_effects/mental.lua
index bceca9ef3b..02b97478bf 100644
--- a/game/modules/tome/data/timed_effects/mental.lua
+++ b/game/modules/tome/data/timed_effects/mental.lua
@@ -2640,8 +2640,8 @@ newEffect{
 	type = "mental",
 	subtype = { psionic=true },
 	status = "detrimental",
-	on_gain = function(self, err) return "#Target# mental functions have been impaired.", "+Sundered Mind" end,
-	on_lose = function(self, err) return "#Target#'s regains it's senses.", "-Sundered Mind" end,
+	on_gain = function(self, err) return "#Target#'s mental functions have been impaired.", "+Sundered Mind" end,
+	on_lose = function(self, err) return "#Target# regains it's senses.", "-Sundered Mind" end,
 	parameters = { power=10 },
 	on_merge = function(self, old_eff, new_eff)
 		self:removeTemporaryValue("combat_mentalresist", old_eff.sunder)
@@ -2658,4 +2658,69 @@ newEffect{
 	deactivate = function(self, eff)
 		self:removeTemporaryValue("combat_mentalresist", eff.sunder)
 	end,
+}
+
+newEffect{
+	name = "BROKEN_DREAM", image = "effects/broken_dream.png",
+	desc = "Broken Dream",
+	long_desc = function(self, eff) return ("The target's dreams have been broken by the dreamforge, reducing it's mental save by %d and reducing it's chance of successfully casting a spell by %d%%."):format(eff.power, eff.power) end,
+	type = "mental",
+	subtype = { psionic=true, morale=true },
+	status = "detrimental",
+	on_gain = function(self, err) return "#Target#'s dreams have been broken.", "+Broken Dream" end,
+	on_lose = function(self, err) return "#Target# regains hope.", "-Broken Dream" end,
+	parameters = { power=10 },
+	activate = function(self, eff)
+		eff.silence = self:addTemporaryValue("spell_failure", eff.power)
+		eff.sunder = self:addTemporaryValue("combat_mentalresist", -eff.power)
+	end,
+	deactivate = function(self, eff)
+		self:removeTemporaryValue("spell_failure", eff.silence)
+		self:removeTemporaryValue("combat_mentalresist", eff.sunder)
+	end,
+}
+
+newEffect{
+	name = "FORGE_SHIELD", image = "talents/block.png",
+	desc = "Forge Shield",
+	long_desc = function(self, eff)
+		local e_string = ""
+		if eff.number == 1 then
+			e_string = DamageType.dam_def[next(eff.d_types)].name
+		else
+			local list = table.keys(eff.d_types)
+			for i = 1, #list do
+				list[i] = DamageType.dam_def[list[i]].name
+			end
+			e_string = table.concat(list, ", ")
+		end
+		local function tchelper(first, rest)
+		  return first:upper()..rest:lower()
+		end
+		return ("Absorbs %d damage from the next blockable attack.  Currently Blocking: %s."):format(eff.power, e_string:gsub("(%a)([%w_']*)", tchelper))
+	end,
+	type = "mental",
+	subtype = { psionic=true },
+	status = "beneficial",
+	parameters = { power=1 },
+	on_gain = function(self, eff) return nil, nil end,
+	on_lose = function(self, eff) return nil, nil end,
+		damage_feedback = function(self, eff, src, value)
+		if eff.particle and eff.particle._shader and eff.particle._shader.shad and src and src.x and src.y then
+			local r = -rng.float(0.2, 0.4)
+			local a = math.atan2(src.y - self.y, src.x - self.x)
+			eff.particle._shader:setUniform("impact", {math.cos(a) * r, math.sin(a) * r})
+			eff.particle._shader:setUniform("impact_tick", core.game.getTime())
+		end
+	end,
+	activate = function(self, eff)
+		if core.shader.active() then
+			eff.particle = self:addParticles(Particles.new("shader_shield", 1, {img="shield2", size_factor=1}, {type="shield", time_factor=12000, color={1.0, 0.5, 0}}))
+		else
+			eff.particle = self:addParticles(Particles.new("time_shield_bubble", 1))
+		end
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle)
+	end,
 }
\ No newline at end of file
-- 
GitLab