diff --git a/game/engine/Map.lua b/game/engine/Map.lua
index 804b93ae31e19740ddf7f83e3a242790c34ffd32..d7e45507d32511f4081ad4922536929eb506e10a 100644
--- a/game/engine/Map.lua
+++ b/game/engine/Map.lua
@@ -376,10 +376,12 @@ end
 -- @param dir the numpad direction of the effect, 5 for a ball effect
 -- @param overlay a simple display entity to draw upon the map
 -- @param update_fct optional function that will be called each time the effect is updated with the effect itself as parameter. Use it to change radius, move around ....
-function _M:addEffect(src, x, y, duration, damtype, dam, radius, dir, angle, overlay, update_fct)
+function _M:addEffect(src, x, y, duration, damtype, dam, radius, dir, angle, overlay, update_fct, friendlyfire)
+	if friendlyfire == nil then friendlyfire = true end
+	print(friendlyfire)
 	table.insert(self.effects, {
 		src=src, x=x, y=y, duration=duration, damtype=damtype, dam=dam, radius=radius, dir=dir, angle=angle, overlay=overlay,
-		update_fct=update_fct,
+		update_fct=update_fct, friendlyfire=friendlyfire
 	})
 	self.changed = true
 end
@@ -429,7 +431,9 @@ function _M:processEffects()
 		-- Now display each grids
 		for lx, ys in pairs(grids) do
 			for ly, _ in pairs(ys) do
-				DamageType:get(e.damtype).projector(e.src, lx, ly, e.damtype, e.dam)
+				if e.friendlyfire or (lx ~= e.src.x and ly ~= e.src.y) then
+					DamageType:get(e.damtype).projector(e.src, lx, ly, e.damtype, e.dam)
+				end
 			end
 		end
 
diff --git a/game/engine/class.lua b/game/engine/class.lua
index e7f10e3166a476c51a83e7bcebe0f119834eb1a2..08a164cbda642e932c3f4d610739aa8a999a23a9 100644
--- a/game/engine/class.lua
+++ b/game/engine/class.lua
@@ -98,7 +98,7 @@ local function basicSerialize(o)
 	if type(o) == "number" or type(o) == "boolean" then
 		return tostring(o)
 	elseif type(o) == "function" then
-		return string.format("%q", string.dump(o))
+		return string.format("loadstring(%q)", string.dump(o))
 	else   -- assume it is a string
 		return string.format("%q", o)
 	end
@@ -157,6 +157,7 @@ local function deserialize(string)
 	local f, err = loadstring(string)
 	if err then print("error deserializing", string, err) end
 	setfenv(f, {
+		loadstring = loadstring,
 		loadObject = function(n)
 --			print("wants to load",n)
 			return engine.Savefile.current_save:loadReal(n)
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 389188e70325ffeb7209dac5f9eb6d6163869c98..85fb1ff4df26b6e0f1ef49dabc40bd8e52bc32df 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -37,6 +37,10 @@ function _M:init(t)
 	self.combat_spellspeed = 0
 	self.combat_spellcrit = 0
 	self.combat_spellpower = 0
+
+	self.combat_physresist = 0
+	self.combat_spellresist = 0
+
 	self.fatigue = 0
 
 	-- Default melee barehanded damage
@@ -67,6 +71,9 @@ function _M:act()
 	-- Compute timed effects
 	self:timedEffects()
 
+	-- Still enough energy to act ?
+	if self.energy.value < game.energy_to_act then return false end
+
 	return true
 end
 
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 9f3a82184bac9396bc103701335dad8a24e887b1..fa86718b34894c1b67ae356ecd62c1eeca897b8a 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -72,11 +72,7 @@ end
 
 function _M:newGame()
 	self.zone = Zone.new("ancient_ruins")
-	self.player = Player.new{
-		name=self.player_name, max_life=25, max_mana=25, max_stamina=25, display='@', color_r=230, color_g=230, color_b=230,
-		unused_stats = 6, unused_talents = 3, image="player.png",
-		move_others=true,
-	}
+	self.player = Player.new{name=self.player_name}
 
 	local birth = Birther.new(self.player, {"base", "race", "subrace", "sex", "class", "subclass" }, function()
 		self:changeLevel(1)
diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua
index 2187211f92ba08b0afa25b30c812f43aa282a6bb..7a1372162c5c04c73c52e975b0230f38b3ed7de8 100644
--- a/game/modules/tome/class/NPC.lua
+++ b/game/modules/tome/class/NPC.lua
@@ -11,7 +11,7 @@ end
 
 function _M:act()
 	-- Do basic actor stuff
-	mod.class.Actor.act(self)
+	if not mod.class.Actor.act(self) then return end
 
 	-- Let the AI think .... beware of Shub !
 	self:doAI()
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index 72cd7bdfc6c4b4461fbd22af63b8a52039728776..eb02f03215c209327ecea76937021c72f142aeee 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -24,10 +24,23 @@ function _M:init(t)
 	self.player = true
 	self.faction = "players"
 
+	self.display='@'
+	self.color_r=230
+	self.color_g=230
+	self.color_b=230
+	self.image="player.png"
+
 	-- Default regen
-	self.mana_regen = self.mana_regen or 1
-	self.stamina_regen = self.stamina_regen or 1
-	self.life_regen = self.life_regen or 0.5
+	self.mana_regen = 1
+	self.stamina_regen = 1
+	self.life_regen = 0.5
+
+	self.max_life=85
+	self.max_mana=85
+	self.max_stamina=85
+	self.unused_stats = 6
+	self.unused_talents = 3
+	self.move_others=true
 
 	self.descriptor = {}
 	self.hotkey = {}
@@ -47,7 +60,7 @@ function _M:move(x, y, force)
 end
 
 function _M:act()
-	mod.class.Actor.act(self)
+	if not mod.class.Actor.act(self) then return end
 
 	game.paused = true
 end
diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua
index d4d108e9e9467f112f4fb5cb8185cf742c0a00cd..c677dd25e0e33e1d6102c429fa1312e6acf27c5a 100644
--- a/game/modules/tome/class/interface/Combat.lua
+++ b/game/modules/tome/class/interface/Combat.lua
@@ -72,6 +72,23 @@ function _M:attackTarget(target)
 	end
 end
 
+--- Computes a logarithmic chance to hit, opposing chance to hit to chance to miss
+-- This will be used for melee attacks, physical and spell resistance
+function _M:checkHit(atk, def, min, max, facotr)
+print("checkHit", atk, def)
+	if atk == 0 then atk = 1 end
+	local hit = nil
+	factor = factor or 5
+	if atk > def then
+		hit = math.log10(1 + 5 * (atk - def) / atk) * 100 + 50
+	else
+		hit = -math.log10(1 + 5 * (def - atk) / atk) * 100 + 50
+	end
+	hit = util.bound(hit, min or 5, max or 95)
+print("=> chance to hit", hit)
+	return rng.percent(hit)
+end
+
 --- Attacks with one weapon
 function _M:attackTargetWith(target, weapon)
 	local damtype = DamageType.PHYSICAL
@@ -79,19 +96,9 @@ function _M:attackTargetWith(target, weapon)
 	-- Does the blow connect? yes .. complex :/
 	local atk, def = self:combatAttack(weapon), target:combatDefense()
 	local dam, apr, armor = self:combatDamage(weapon), self:combatAPR(weapon), target:combatArmor()
-	print(atk, def, "::", dam, apr, armor)
-	if afk == 0 then atk = 1 end
-	local hit = nil
-	if atk > def then
-		hit = math.log10(1 + 5 * (atk - def) / atk) * 100 + 50
-	else
-		hit = -math.log10(1 + 5 * (def - atk) / atk) * 100 + 50
-	end
-	hit = util.bound(hit, 5, 95)
-	print("hit: ", hit, "from", atk, def)
 
 	-- If hit is over 0 it connects, if it is 0 we still have 50% chance
-	if rng.percent(hit) then
+	if self:checkHit(atk, def) then
 		local dam = dam - math.max(0, armor - apr)
 		dam = self:physicalCrit(dam, weapon)
 		DamageType:get(damtype).projector(self, target.x, target.y, damtype, dam)
@@ -181,3 +188,13 @@ function _M:spellCrit(dam)
 	end
 	return dam
 end
+
+--- Computes physical resistance
+function _M:combatPhysicalResist()
+	return self.combat_physresist + (self:getCon() + self:getStr()) * 0.5
+end
+
+--- Computes spell resistance
+function _M:combatSpellResist()
+	return self.combat_spellresist + (self:getMag() + self:getWil()) * 0.5
+end
diff --git a/game/modules/tome/data/birth/classes.lua b/game/modules/tome/data/birth/classes.lua
index 57c8b1b9a12c276b1a391fbfd1caf2ebc43665cb..bb5da8c77bd525df9140c04a0471ccae212a2582 100644
--- a/game/modules/tome/data/birth/classes.lua
+++ b/game/modules/tome/data/birth/classes.lua
@@ -59,7 +59,7 @@ newBirthDescriptor{
 		["spell/arcane"]=true,
 		["spell/fire"]=true,
 		["spell/earth"]=true,
-		["spell/cold"]=true,
+		["spell/water"]=true,
 		["spell/air"]=true,
 		["spell/mind"]=true,
 		["spell/temporal"]=true,
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index 66d9aee8de45c2569d4ff1e076e6dff5887645ea..f4cebca9b1cba8d2a3e0c9bf83d23295a51f36cf 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -49,7 +49,7 @@ newDamageType{
 		local target = game.level.map(x, y, Map.ACTOR)
 		if target then
 			-- Set on fire!
-			target:setEffect(target.EFF_BURNING, 3, {src=src, power=dam / 2 / 3})
+			target:setEffect(target.EFF_BURNING, 3, {src=src, power=dam / 6})
 		end
 	end,
 }
@@ -57,3 +57,22 @@ newDamageType{
 newDamageType{
 	name = "netherflame", type = "NETHERFLAME",
 }
+
+newDamageType{
+	name = "freeze", type = "FREEZE",
+	projector = function(src, x, y, type, dam)
+		local target = game.level.map(x, y, Map.ACTOR)
+		if target then
+			-- Freeze it, if we pass the test
+			local sx, sy = game.level.map:getTileToScreen(x, y)
+			if target:checkHit(src:combatSpellpower(), target:combatSpellResist(), 0, 95, 15) then
+				target:setEffect(target.EFF_FROZEN, dam, {src=src})
+
+				game.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, -3, "Frozen!", {0,255,155})
+			else
+				game.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, -3, "Resist!", {0,255,155})
+				game.logSeen(target, "%s resists!", target.name:capitalize())
+			end
+		end
+	end,
+}
diff --git a/game/modules/tome/data/talents/spells/water.lua b/game/modules/tome/data/talents/spells/water.lua
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a2b6540f57027f3271cb9d374e66fae8e15b33dc 100644
--- a/game/modules/tome/data/talents/spells/water.lua
+++ b/game/modules/tome/data/talents/spells/water.lua
@@ -0,0 +1,56 @@
+newTalent{
+	name = "Freeze",
+	type = {"spell/water", 1},
+	mana = 14,
+	cooldown = 3,
+	tactical = {
+		ATTACK = 10,
+	},
+	action = function(self)
+		local t = {type="hit", range=20}
+		local x, y = self:getTarget(t)
+		if not x or not y then return nil end
+		self:project(t, x, y, DamageType.COLD, self:spellCrit(7 + self:combatSpellpower(0.7)))
+		self:project(t, x, y, DamageType.FREEZE, 2)
+		return true
+	end,
+	require = { stat = { mag=14 }, },
+	info = function(self)
+		return ([[Condenses ambiant water on a target, freezing it for a short while.
+		The damage will increase with the Magic stat]]):format(7 + self:combatSpellpower(0.7))
+	end,
+}
+
+newTalent{
+	name = "Ice Storm",
+	type = {"spell/water",2},
+	mana = 45,
+	cooldown = 30,
+	tactical = {
+		ATTACKAREA = 20,
+	},
+	action = function(self)
+		local duration = 5 + self:combatSpellpower(0.25)
+		local radius = 3
+		local dam = 12 + self:combatSpellpower(0.20)
+		-- Add a lasting map effect
+		game.level.map:addEffect(self,
+			self.x, self.y, duration,
+			DamageType.COLD, dam,
+			radius,
+			5, nil,
+			engine.Entity.new{alpha=100, display='', color_br=30, color_bg=60, color_bb=200},
+			function(e)
+				e.x = e.src.x
+				e.y = e.src.y
+			end,
+			false
+		)
+		return true
+	end,
+	require = { stat = { mag=16 }, },
+	info = function(self)
+		return ([[A furious ice storm rages around the caster doing %0.2f cold damage in a radius of 3 each turns for %d turns.
+		The damage and duration will increase with the Magic stat]]):format(12 + self:combatSpellpower(0.20), 5 + self:combatSpellpower(0.25))
+	end,
+}
diff --git a/game/modules/tome/data/timed_effects.lua b/game/modules/tome/data/timed_effects.lua
index d2bcd39add0721946f285be3d4538465d4c67a48..2af1bb3d0b543ec398baaf52d43f0fa336f4bc6e 100644
--- a/game/modules/tome/data/timed_effects.lua
+++ b/game/modules/tome/data/timed_effects.lua
@@ -55,3 +55,53 @@ newEffect{
 		DamageType:get(DamageType.FIRE).projector(eff.src, self.x, self.y, DamageType.FIRE, eff.power)
 	end,
 }
+
+newEffect{
+	name = "FROZEN",
+	desc = "Frozen",
+	type = "magical",
+	status = "detrimental",
+	parameters = {},
+	on_gain = function(self, err) return "#Target# is frozen!" end,
+	on_lose = function(self, err) return "#Target# warms up.", "-Frozen" end,
+	activate = function(self, eff)
+		-- Change color
+		eff.old_r = self.color_r
+		eff.old_g = self.color_g
+		eff.old_b = self.color_b
+		self.color_r = 0
+		self.color_g = 255
+		self.color_b = 155
+		game.level.map:updateMap(self.x, self.y)
+
+		-- Frozen, cannot act
+		self.energy.value = 0
+	end,
+	on_timeout = function(self, eff)
+		-- Frozen, cannot act
+		self.energy.value = 0
+	end,
+	deactivate = function(self, eff)
+		self.color_r = eff.old_r
+		self.color_g = eff.old_g
+		self.color_b = eff.old_b
+	end,
+}
+
+newEffect{
+	name = "STUNNED",
+	desc = "STUN",
+	type = "physical",
+	status = "detrimental",
+	parameters = {},
+	on_gain = function(self, err) return "#Target# is stunned!", "+Stunned" end,
+	on_lose = function(self, err) return "#Target# is not stunned anymore.", "-Stunned" end,
+	activate = function(self, eff)
+		-- Frozen, cannot act
+		self.energy.value = 0
+	end,
+	on_timeout = function(self, eff)
+		-- Frozen, cannot act
+		self.energy.value = 0
+	end,
+}
diff --git a/ideas/spells.ods b/ideas/spells.ods
index 3585db60e4592842bed131312433b5eaa82f8a04..991558f5e8c5886bcdc9daa6f3d6876aa016f51e 100644
Binary files a/ideas/spells.ods and b/ideas/spells.ods differ