diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua
index 50d6b87b9e804308c819c436f17599ff348d0906..47561ec21ac128061a566fece839f9fecf9c6026 100644
--- a/game/modules/tome/class/GameState.lua
+++ b/game/modules/tome/class/GameState.lua
@@ -160,6 +160,8 @@ function _M:generateRandart(add)
 	print("Creating randart "..o.name.." with level "..lev)
 	print(" == using themes", table.concat(table.keys(themes), ','))
 
+	o.cost = o.cost + points * 7
+
 	-- Select some powers
 	for i = 1, nb_powers do
 		local list = game.zone:computeRarities("powers", powers_list, game.level, themes_fct)
diff --git a/game/modules/tome/data/general/objects/scrolls.lua b/game/modules/tome/data/general/objects/scrolls.lua
index aede43a31d6043e0eda795df038626167ae62ffd..309e94b194dc4c73612a285681d40d2154f710b6 100644
--- a/game/modules/tome/data/general/objects/scrolls.lua
+++ b/game/modules/tome/data/general/objects/scrolls.lua
@@ -88,13 +88,13 @@ newEntity{
 newEntity{ base = "BASE_INFUSION",
 	name = "healing infusion",
 	level_range = {7, 50},
-	rarity = 9,
+	rarity = 16,
 	cost = 10,
 	material_level = 1,
 
 	inscription_data = {
-		cooldown = resolvers.rngrange(4, 12),
-		heal = resolvers.mbonus(300, 40),
+		cooldown = resolvers.rngrange(6, 12),
+		heal = resolvers.mbonus(300, 40, function(e, v) return v * 0.06 end),
 		use_stat_mod = 2,
 	},
 	inscription_talent = "INFUSION:_HEALING",
@@ -103,14 +103,14 @@ newEntity{ base = "BASE_INFUSION",
 newEntity{ base = "BASE_INFUSION",
 	name = "regeneration infusion",
 	level_range = {1, 50},
-	rarity = 9,
+	rarity = 15,
 	cost = 10,
 	material_level = 1,
 
 	inscription_data = {
-		cooldown = resolvers.rngrange(9, 12),
+		cooldown = resolvers.rngrange(10, 15),
 		dur = 5,
-		heal = resolvers.mbonus(500, 60),
+		heal = resolvers.mbonus(500, 60, function(e, v) return v * 0.06 end),
 		use_stat_mod = 2.1,
 	},
 	inscription_talent = "INFUSION:_REGENERATION",
@@ -119,7 +119,7 @@ newEntity{ base = "BASE_INFUSION",
 newEntity{ base = "BASE_INFUSION",
 	name = "wild infusion",
 	level_range = {1, 50},
-	rarity = 12,
+	rarity = 13,
 	cost = 20,
 	material_level = 1,
 
@@ -146,13 +146,13 @@ newEntity{ base = "BASE_INFUSION",
 newEntity{ base = "BASE_INFUSION",
 	name = "movement infusion",
 	level_range = {10, 50},
-	rarity = 9,
+	rarity = 15,
 	cost = 30,
 	material_level = 3,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(10, 15),
-		dur = resolvers.mbonus(5, 2),
+		dur = resolvers.mbonus(5, 2, function(e, v) return v * 1 end),
 		use_stat_mod = 0.05,
 	},
 	inscription_talent = "INFUSION:_MOVEMENT",
@@ -161,13 +161,13 @@ newEntity{ base = "BASE_INFUSION",
 newEntity{ base = "BASE_INFUSION",
 	name = "sun infusion",
 	level_range = {1, 50},
-	rarity = 9,
+	rarity = 13,
 	cost = 10,
 	material_level = 1,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(6, 12),
-		range = resolvers.mbonus(5, 5),
+		range = resolvers.mbonus(5, 5, function(e, v) return v * 0.1 end),
 		use_stat_mod = 0.05,
 	},
 	inscription_talent = "INFUSION:_SUN",
@@ -176,14 +176,14 @@ newEntity{ base = "BASE_INFUSION",
 newEntity{ base = "BASE_INFUSION",
 	name = "strength infusion",
 	level_range = {25, 50},
-	rarity = 12,
+	rarity = 16,
 	cost = 40,
 	material_level = 3,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(20, 30),
 		dur = resolvers.mbonus(7, 7),
-		power = resolvers.mbonus(4, 4),
+		power = resolvers.mbonus(4, 4, function(e, v) return v * 3 end),
 		use_stat_mod = 0.04,
 	},
 	inscription_talent = "INFUSION:_STRENGTH",
@@ -192,14 +192,14 @@ newEntity{ base = "BASE_INFUSION",
 newEntity{ base = "BASE_INFUSION",
 	name = "will infusion",
 	level_range = {25, 50},
-	rarity = 12,
+	rarity = 16,
 	cost = 40,
 	material_level = 3,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(20, 30),
 		dur = resolvers.mbonus(7, 7),
-		power = resolvers.mbonus(4, 4),
+		power = resolvers.mbonus(4, 4, function(e, v) return v * 3 end),
 		use_stat_mod = 0.04,
 	},
 	inscription_talent = "INFUSION:_WILL",
@@ -208,13 +208,13 @@ newEntity{ base = "BASE_INFUSION",
 newEntity{ base = "BASE_RUNE",
 	name = "phase door rune",
 	level_range = {1, 50},
-	rarity = 9,
+	rarity = 15,
 	cost = 10,
 	material_level = 1,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(5, 9),
-		range = resolvers.mbonus(10, 5),
+		range = resolvers.mbonus(10, 5, function(e, v) return v * 1 end),
 		use_stat_mod = 0.07,
 	},
 	inscription_talent = "RUNE:_PHASE_DOOR",
@@ -223,13 +223,13 @@ newEntity{ base = "BASE_RUNE",
 newEntity{ base = "BASE_RUNE",
 	name = "controlled phase door rune",
 	level_range = {35, 50},
-	rarity = 14,
+	rarity = 17,
 	cost = 50,
 	material_level = 4,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(7, 12),
-		range = resolvers.mbonus(6, 5),
+		range = resolvers.mbonus(6, 5, function(e, v) return v * 3 end),
 		use_stat_mod = 0.05,
 	},
 	inscription_talent = "RUNE:_CONTROLLED_PHASE_DOOR",
@@ -238,13 +238,13 @@ newEntity{ base = "BASE_RUNE",
 newEntity{ base = "BASE_RUNE",
 	name = "teleportation rune",
 	level_range = {10, 50},
-	rarity = 9,
+	rarity = 15,
 	cost = 10,
 	material_level = 2,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(9, 14),
-		range = resolvers.mbonus(100, 20),
+		range = resolvers.mbonus(100, 20, function(e, v) return v * 0.03 end),
 		use_stat_mod = 1,
 	},
 	inscription_talent = "RUNE:_TELEPORTATION",
@@ -253,14 +253,14 @@ newEntity{ base = "BASE_RUNE",
 newEntity{ base = "BASE_RUNE",
 	name = "shielding rune",
 	level_range = {12, 50},
-	rarity = 9,
+	rarity = 15,
 	cost = 20,
 	material_level = 3,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(14, 24),
 		dur = resolvers.mbonus(5, 3),
-		power = resolvers.mbonus(400, 50),
+		power = resolvers.mbonus(400, 50, function(e, v) return v * 0.06 end),
 		use_stat_mod = 2.3,
 	},
 	inscription_talent = "RUNE:_SHIELDING",
@@ -269,14 +269,14 @@ newEntity{ base = "BASE_RUNE",
 newEntity{ base = "BASE_RUNE",
 	name = "invisibility rune",
 	level_range = {18, 50},
-	rarity = 12,
+	rarity = 19,
 	cost = 40,
 	material_level = 3,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(14, 24),
-		dur = resolvers.mbonus(9, 4),
-		power = resolvers.mbonus(8, 7),
+		dur = resolvers.mbonus(9, 4, function(e, v) return v * 1 end),
+		power = resolvers.mbonus(8, 7, function(e, v) return v * 1 end),
 		use_stat_mod = 0.08,
 		nb_uses = resolvers.mbonus(7, 4),
 	},
@@ -286,14 +286,14 @@ newEntity{ base = "BASE_RUNE",
 newEntity{ base = "BASE_RUNE",
 	name = "speed rune",
 	level_range = {23, 50},
-	rarity = 12,
+	rarity = 16,
 	cost = 40,
 	material_level = 3,
 
 	inscription_data = {
 		cooldown = resolvers.rngrange(14, 24),
 		dur = resolvers.mbonus(4, 3),
-		power = resolvers.mbonus(30, 30),
+		power = resolvers.mbonus(30, 30, function(e, v) return v * 0.3 end),
 		use_stat_mod = 0.3,
 		nb_uses = resolvers.mbonus(7, 4),
 	},
@@ -303,7 +303,7 @@ newEntity{ base = "BASE_RUNE",
 newEntity{ base = "BASE_RUNE",
 	name = "vision rune",
 	level_range = {15, 50},
-	rarity = 10,
+	rarity = 16,
 	cost = 30,
 	material_level = 2,
 
@@ -311,8 +311,72 @@ newEntity{ base = "BASE_RUNE",
 		cooldown = resolvers.rngrange(20, 30),
 		range = resolvers.mbonus(10, 8),
 		dur = resolvers.mbonus(20, 12),
-		power = resolvers.mbonus(20, 10),
+		power = resolvers.mbonus(20, 10, function(e, v) return v * 0.3 end),
 		use_stat_mod = 0.14,
 	},
 	inscription_talent = "RUNE:_VISION",
 }
+
+newEntity{ base = "BASE_RUNE",
+	name = "heat beam rune",
+	level_range = {25, 50},
+	rarity = 16,
+	cost = 20,
+	material_level = 3,
+
+	inscription_data = {
+		cooldown = resolvers.rngrange(15, 25),
+		range = resolvers.mbonus(5, 4),
+		power = resolvers.mbonus(300, 60, function(e, v) return v * 0.1 end),
+		use_stat_mod = 1.8,
+	},
+	inscription_talent = "RUNE:_HEAT_BEAM",
+}
+
+newEntity{ base = "BASE_RUNE",
+	name = "frozen spear rune",
+	level_range = {25, 50},
+	rarity = 16,
+	cost = 20,
+	material_level = 3,
+
+	inscription_data = {
+		cooldown = resolvers.rngrange(15, 25),
+		range = resolvers.mbonus(5, 4),
+		power = resolvers.mbonus(300, 60, function(e, v) return v * 0.1 end),
+		use_stat_mod = 1.8,
+	},
+	inscription_talent = "RUNE:_FROZEN_SPEAR",
+}
+
+newEntity{ base = "BASE_RUNE",
+	name = "acid wave rune",
+	level_range = {25, 50},
+	rarity = 16,
+	cost = 20,
+	material_level = 3,
+
+	inscription_data = {
+		cooldown = resolvers.rngrange(15, 25),
+		range = resolvers.mbonus(3, 2),
+		power = resolvers.mbonus(250, 40, function(e, v) return v * 0.1 end),
+		use_stat_mod = 1.8,
+	},
+	inscription_talent = "RUNE:_ACID_WAVE",
+}
+
+newEntity{ base = "BASE_RUNE",
+	name = "lightning rune",
+	level_range = {25, 50},
+	rarity = 16,
+	cost = 20,
+	material_level = 3,
+
+	inscription_data = {
+		cooldown = resolvers.rngrange(15, 25),
+		range = resolvers.mbonus(5, 4),
+		power = resolvers.mbonus(280, 50, function(e, v) return v * 0.1 end),
+		use_stat_mod = 1.8,
+	},
+	inscription_talent = "RUNE:_LIGHTNING",
+}
diff --git a/game/modules/tome/data/gfx/particles/ball_acid.lua b/game/modules/tome/data/gfx/particles/ball_acid.lua
index 71e5dedc7d9a065cf118d835cf4f38108f7f26a4..58958d8ba19b3aaa7eb5a02f8eac4fcdb1fd31d3 100644
--- a/game/modules/tome/data/gfx/particles/ball_acid.lua
+++ b/game/modules/tome/data/gfx/particles/ball_acid.lua
@@ -17,28 +17,29 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
-local nb = 0
+local nb = 12
+local dir
+local radius = radius or 6
+
 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 r = 0
 	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)
+	local vel = sradius * ((24 - nb * 1.4) / 24) / 12
 
 	return {
 		trail = 1,
-		life = 10,
-		size = 3, sizev = 0, sizea = 0,
+		life = 12,
+		size = 12 - (12 - nb) * 0.7, 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 / 10, velv = 0, vela = 0,
+		vel = rng.float(vel * 0.6, vel * 1.2), velv = 0, vela = 0,
 
 		r = 0,   rv = 0, ra = 0,
 		g = rng.range(80, 255)/255,   gv = 0, ga = 0,
@@ -47,17 +48,12 @@ return { generator = function()
 	}
 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
+	if nb > 0 then
+		local i = math.min(nb, 6)
+		i = (i * i) * radius
+		self.ps:emit(i)
+		nb = nb - 1
 	end
 end,
-5*radius*266
+30*radius*7*12,
+"particle_cloud"
diff --git a/game/modules/tome/data/gfx/particles/bolt_ice.lua b/game/modules/tome/data/gfx/particles/bolt_ice.lua
new file mode 100644
index 0000000000000000000000000000000000000000..bb37efe2c5ae116ccf069a0f017546a192de2e98
--- /dev/null
+++ b/game/modules/tome/data/gfx/particles/bolt_ice.lua
@@ -0,0 +1,51 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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
+
+return { generator = function()
+	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, 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 = 6,
+		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 / 6, velv = 0, vela = 0,
+
+		r = 0,   rv = 0, ra = 0,
+		g = rng.range(170, 210)/255,   gv = 0, ga = 0,
+		b = rng.range(200, 255)/255,   gv = 0, ga = 0,
+		a = rng.range(230, 225)/255,   av = 0, aa = 0,
+	}
+end, },
+function(self)
+	self.ps:emit(30)
+end,
+30*6
diff --git a/game/modules/tome/data/talents/misc/inscriptions.lua b/game/modules/tome/data/talents/misc/inscriptions.lua
index 014bbd1735d8f97980c3733c4ee4dd55acd22d56..dfd82674c63002d5b7f63880d48e08a601870f3b 100644
--- a/game/modules/tome/data/talents/misc/inscriptions.lua
+++ b/game/modules/tome/data/talents/misc/inscriptions.lua
@@ -32,6 +32,10 @@ local newInscription = function(t)
 				return t.name
 			end
 		end
+		tt.cooldown = function(self, t)
+			local data = self:getInscriptionData(t.short_name)
+			return data.cooldown
+		end
 		newTalent(tt)
 	end
 end
@@ -43,10 +47,6 @@ newInscription{
 	name = "Infusion: Regeneration",
 	type = {"inscriptions/infusions", 1},
 	points = 1,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:setEffect(self.EFF_REGENERATION, data.dur, {power=(data.heal + data.inc_stat) / data.dur})
@@ -62,10 +62,6 @@ newInscription{
 	name = "Infusion: Healing",
 	type = {"inscriptions/infusions", 1},
 	points = 1,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:heal(data.heal + data.inc_stat)
@@ -82,10 +78,6 @@ newInscription{
 	type = {"inscriptions/infusions", 1},
 	points = 1,
 	no_energy = true,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 
@@ -127,10 +119,6 @@ newInscription{
 	name = "Infusion: Movement",
 	type = {"inscriptions/infusions", 1},
 	points = 1,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:setEffect(self.EFF_FREE_ACTION, data.dur + data.inc_stat, {power=1})
@@ -146,10 +134,6 @@ newInscription{
 	name = "Infusion: Sun",
 	type = {"inscriptions/infusions", 1},
 	points = 1,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:project({type="ball", range=0, friendlyfire=true, radius=data.range + data.inc_stat}, self.x, self.y, engine.DamageType.LITE, 1)
@@ -166,10 +150,6 @@ newInscription{
 	name = "Infusion: Strength",
 	type = {"inscriptions/infusions", 1},
 	points = 1,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:setEffect(self.EFF_STRENGTH, data.dur, {power=data.power + data.inc_stat})
@@ -185,10 +165,6 @@ newInscription{
 	name = "Infusion: Will",
 	type = {"inscriptions/infusions", 1},
 	points = 1,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:setEffect(self.EFF_WILL, data.dur, {power=data.power + data.inc_stat})
@@ -208,10 +184,6 @@ newInscription{
 	type = {"inscriptions/runes", 1},
 	points = 1,
 	is_spell = true,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		game.level.map:particleEmitter(self.x, self.y, 1, "teleport")
@@ -230,10 +202,6 @@ newInscription{
 	type = {"inscriptions/runes", 1},
 	points = 1,
 	is_spell = true,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		local tg = {type="ball", nolock=true, pass_terrain=true, nowarning=true, range=data.range + data.inc_stat, radius=3, requires_knowledge=false}
@@ -258,10 +226,6 @@ newInscription{
 	type = {"inscriptions/runes", 1},
 	points = 1,
 	is_spell = true,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		game.level.map:particleEmitter(self.x, self.y, 1, "teleport")
@@ -280,10 +244,6 @@ newInscription{
 	type = {"inscriptions/runes", 1},
 	points = 1,
 	is_spell = true,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:setEffect(self.EFF_DAMAGE_SHIELD, data.dur, {power=data.power + data.inc_stat})
@@ -300,10 +260,6 @@ newInscription{
 	type = {"inscriptions/runes", 1},
 	points = 1,
 	is_spell = true,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:setEffect(self.EFF_INVISIBILITY, data.dur, {power=data.power + data.inc_stat})
@@ -321,10 +277,6 @@ newInscription{
 	type = {"inscriptions/runes", 1},
 	points = 1,
 	is_spell = true,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:setEffect(self.EFF_SPEED, data.dur, {power=(data.power + data.inc_stat) / 100})
@@ -342,10 +294,6 @@ newInscription{
 	type = {"inscriptions/runes", 1},
 	points = 1,
 	is_spell = true,
-	cooldown = function(self, t)
-		local data = self:getInscriptionData(t.short_name)
-		return data.cooldown
-	end,
 	action = function(self, t)
 		local data = self:getInscriptionData(t.short_name)
 		self:magicMap(data.range, self.x, self.y, function(x, y)
@@ -366,3 +314,104 @@ newInscription{
 		format(data.range, data.power + data.inc_stat, data.dur)
 	end,
 }
+
+newInscription{
+	name = "Rune: Heat Beam",
+	type = {"inscriptions/runes", 1},
+	points = 1,
+	is_spell = true,
+	range = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		return data.range
+	end,
+	action = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		local tg = {type="beam", range=self:getTalentRange(t), talent=t}
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		self:project(tg, x, y, DamageType.FIREBURN, {dur=5, initial=0, dam=data.power + data.inc_stat})
+		local _ _, x, y = self:canProject(tg, x, y)
+		game.level.map:particleEmitter(self.x, self.y, tg.radius, "flamebeam", {tx=x-self.x, ty=y-self.y})
+		game:playSoundNear(self, "talents/fire")
+		return true
+	end,
+	info = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		return ([[Activate the rune to fire a beam of heat doing %0.2f fire damage over 5 turns.]]):format(damDesc(self, DamageType.FIRE, data.power + data.inc_stat))
+	end,
+}
+
+newInscription{
+	name = "Rune: Frozen Spear",
+	type = {"inscriptions/runes", 1},
+	points = 1,
+	is_spell = true,
+	range = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		return data.range
+	end,
+	action = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		local tg = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="bolt_ice", trail="icetrail"}}
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		self:projectile(tg, x, y, DamageType.ICE, data.power + data.inc_stat, {type="freeze"})
+		game:playSoundNear(self, "talents/ice")
+		return true
+	end,
+	info = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		return ([[Activate the rune to fire a bolt of ice doing %0.2f cold damage with a chance to freeze the target.]]):format(damDesc(self, DamageType.COLD, data.power + data.inc_stat))
+	end,
+}
+
+newInscription{
+	name = "Rune: Acid Wave",
+	type = {"inscriptions/runes", 1},
+	points = 1,
+	is_spell = true,
+	range = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		return data.range
+	end,
+	action = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t}
+		self:projectile(tg, self.x, self.y, DamageType.ACID, data.power + data.inc_stat)
+		game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_acid", {radius=tg.radius})
+		game:playSoundNear(self, "talents/slime")
+		return true
+	end,
+	info = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		return ([[Activate the rune to fire a self centered acid wave, doing %0.2f acid damage.]]):format(damDesc(self, DamageType.ACID, data.power + data.inc_stat))
+	end,
+}
+
+newInscription{
+	name = "Rune: Lightning",
+	type = {"inscriptions/runes", 1},
+	points = 1,
+	is_spell = true,
+	range = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		return data.range
+	end,
+	action = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		local tg = {type="beam", range=self:getTalentRange(t), talent=t}
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		local dam = data.power + data.inc_stat
+		self:project(tg, x, y, DamageType.LIGHTNING, rng.avg(dam / 3, dam, 3))
+		local _ _, x, y = self:canProject(tg, x, y)
+		game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(x-self.x), math.abs(y-self.y)), "lightning", {tx=x-self.x, ty=y-self.y})
+		game:playSoundNear(self, "talents/lightning")
+		return true
+	end,
+	info = function(self, t)
+		local data = self:getInscriptionData(t.short_name)
+		local dam = damDesc(self, DamageType.LIGHTNING, data.power + data.inc_stat)
+		return ([[Activate the rune to fire a beam of lightning, doing %0.2f to %0.2f lightning damage.]]):format(dam / 3, dam)
+	end,
+}
diff --git a/game/modules/tome/resolvers.lua b/game/modules/tome/resolvers.lua
index 0e7c32fbaf2005c76109f9a8a432a2cf78f31d31..0967a37eae05ba876778d0d26f19be9375b599ef 100644
--- a/game/modules/tome/resolvers.lua
+++ b/game/modules/tome/resolvers.lua
@@ -205,6 +205,23 @@ function resolvers.calc.mbonus_material(t, e)
 	return v
 end
 
+--- Random bonus based on level and material quality
+resolvers.current_level = 1
+function resolvers.mbonusl(max, add, pricefct)
+	return {__resolver="mbonus", max, add, pricefct}
+end
+function resolvers.calc.mbonus(t, e)
+	local v = rng.mbonus(t[1], resolvers.current_level, resolvers.mbonus_max_level) + (t[2] or 0)
+
+	if e.cost and t[3] then
+		local ap, nv = t[3](e, v)
+		e.cost = e.cost + ap
+		v = nv or v
+	end
+
+	return v
+end
+
 --- Generic resolver, takes a function, executes at the end
 function resolvers.genericlast(fct)
 	return {__resolver="genericlast", __resolve_last=true, fct}