From f2991857a94cd5ce865beeaf7f8ba020f1ccd987 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Tue, 5 Oct 2010 16:26:55 +0000
Subject: [PATCH] The main menu interface is now a module like any others,
 called "boot" The main menu will now have a random animated background with
 an AI-controlled player running around in a forest, blasting things

git-svn-id: http://svn.net-core.org/repos/t-engine4@1423 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/engines/default/engine/Game.lua          |   8 +-
 game/engines/default/engine/Module.lua        |  49 +-
 .../default/engine/dialogs/VideoOptions.lua   |   9 +
 game/engines/default/engine/utils.lua         |  13 +-
 game/engines/default/engine/version.lua       |   2 +-
 game/loader/init.lua                          |   5 +
 game/modules/boot/ai/player.lua               |  58 +++
 game/modules/boot/class/Actor.lua             | 179 +++++++
 game/modules/boot/class/Game.lua              | 469 ++++++++++++++++++
 game/modules/boot/class/Grid.lua              | 107 ++++
 game/modules/boot/class/NPC.lua               |  53 ++
 game/modules/boot/class/Player.lua            | 108 ++++
 game/modules/boot/class/interface/Combat.lua  |  56 +++
 game/modules/boot/data/birth/descriptors.lua  |  56 +++
 game/modules/boot/data/damage_types.lua       |  61 +++
 .../modules/boot/data/general/grids/basic.lua |  83 ++++
 .../boot/data/general/grids/forest.lua        |  46 ++
 .../modules/boot/data/general/grids/water.lua |  40 ++
 .../modules/boot/data/general/npcs/canine.lua |  86 ++++
 .../boot/data/general/npcs/skeleton.lua       |  72 +++
 game/modules/boot/data/general/npcs/troll.lua |  77 +++
 .../data/gfx/npc/armored_skeleton_warrior.png | Bin 0 -> 1582 bytes
 game/modules/boot/data/gfx/npc/canine_dw.png  | Bin 0 -> 3466 bytes
 game/modules/boot/data/gfx/npc/canine_fox.png | Bin 0 -> 3178 bytes
 game/modules/boot/data/gfx/npc/canine_gw.png  | Bin 0 -> 3640 bytes
 game/modules/boot/data/gfx/npc/canine_w.png   | Bin 0 -> 3319 bytes
 .../modules/boot/data/gfx/npc/canine_warg.png | Bin 0 -> 3694 bytes
 game/modules/boot/data/gfx/npc/canine_ww.png  | Bin 0 -> 3847 bytes
 .../gfx/npc/degenerated_skeleton_warrior.png  | Bin 0 -> 994 bytes
 .../boot/data/gfx/npc/skeleton_mage.png       | Bin 0 -> 1388 bytes
 .../boot/data/gfx/npc/skeleton_warrior.png    | Bin 0 -> 1153 bytes
 game/modules/boot/data/gfx/npc/troll_c.png    | Bin 0 -> 2725 bytes
 game/modules/boot/data/gfx/npc/troll_f.png    | Bin 0 -> 2213 bytes
 game/modules/boot/data/gfx/npc/troll_m.png    | Bin 0 -> 2331 bytes
 game/modules/boot/data/gfx/npc/troll_mt.png   | Bin 0 -> 2938 bytes
 game/modules/boot/data/gfx/npc/troll_s.png    | Bin 0 -> 2419 bytes
 game/modules/boot/data/gfx/particles/acid.lua |  38 ++
 .../boot/data/gfx/particles/bolt_fire.lua     |  51 ++
 .../boot/data/gfx/particles/fireflash.lua     |  96 ++++
 .../boot/data/gfx/particles/firetrail.lua     |  56 +++
 .../modules/boot/data/gfx/particles/flame.lua |  38 ++
 .../boot/data/gfx/particles/golden_shield.lua |  46 ++
 .../boot/data/gfx/particles/lightning.lua     |  83 ++++
 .../boot/data/gfx/particles/mana_beam.lua     |  58 +++
 .../boot/data/gfx/particles/sunburst.lua      | 132 +++++
 .../boot/data/gfx/shaders/main_fbo.frag       | 172 +++++++
 .../boot/data/gfx/shaders/main_fbo.lua        |  28 ++
 game/modules/boot/data/gfx/shaders/water.frag |  21 +
 game/modules/boot/data/gfx/shaders/water.lua  |  29 ++
 game/modules/boot/data/gfx/terrain/grass.png  | Bin 0 -> 684 bytes
 .../boot/data/gfx/terrain/grass_flower3.png   | Bin 0 -> 1096 bytes
 .../boot/data/gfx/terrain/tree_alpha1.png     | Bin 0 -> 829 bytes
 .../boot/data/gfx/terrain/tree_alpha2.png     | Bin 0 -> 777 bytes
 .../boot/data/gfx/terrain/tree_alpha3.png     | Bin 0 -> 1016 bytes
 .../boot/data/gfx/terrain/tree_alpha4.png     | Bin 0 -> 4267 bytes
 .../boot/data/gfx/terrain/tree_alpha5.png     | Bin 0 -> 4267 bytes
 .../boot/data/gfx/terrain/water_floor.png     | Bin 0 -> 154 bytes
 .../data/gfx/terrain/water_floor_alpha.png    | Bin 0 -> 177 bytes
 game/modules/boot/data/rooms/pilar.lua        |  26 +
 game/modules/boot/data/rooms/simple.lua       |  37 ++
 game/modules/boot/data/talents.lua            | 168 +++++++
 game/modules/boot/data/timed_effects.lua      |  47 ++
 .../modules/boot/data/zones/dungeon/grids.lua |  22 +
 game/modules/boot/data/zones/dungeon/npcs.lua |  22 +
 .../boot/data/zones/dungeon/objects.lua       |  18 +
 .../modules/boot/data/zones/dungeon/traps.lua |  18 +
 game/modules/boot/data/zones/dungeon/zone.lua |  52 ++
 game/modules/boot/dialogs/LoadGame.lua        | 111 +++++
 game/modules/boot/dialogs/MainMenu.lua        |  59 +++
 game/modules/boot/dialogs/NewGame.lua         |  69 +++
 game/modules/boot/dialogs/Profile.lua         |  86 ++++
 game/modules/boot/dialogs/ProfileLogin.lua    |  85 ++++
 game/modules/boot/init.lua                    |  30 ++
 game/modules/boot/load.lua                    |  64 +++
 .../data/general/objects/world-artifacts.lua  |   2 +-
 src/core_lua.c                                |  19 +-
 src/main.c                                    |  26 +-
 77 files changed, 3412 insertions(+), 34 deletions(-)
 create mode 100644 game/modules/boot/ai/player.lua
 create mode 100644 game/modules/boot/class/Actor.lua
 create mode 100644 game/modules/boot/class/Game.lua
 create mode 100644 game/modules/boot/class/Grid.lua
 create mode 100644 game/modules/boot/class/NPC.lua
 create mode 100644 game/modules/boot/class/Player.lua
 create mode 100644 game/modules/boot/class/interface/Combat.lua
 create mode 100644 game/modules/boot/data/birth/descriptors.lua
 create mode 100644 game/modules/boot/data/damage_types.lua
 create mode 100644 game/modules/boot/data/general/grids/basic.lua
 create mode 100644 game/modules/boot/data/general/grids/forest.lua
 create mode 100644 game/modules/boot/data/general/grids/water.lua
 create mode 100644 game/modules/boot/data/general/npcs/canine.lua
 create mode 100644 game/modules/boot/data/general/npcs/skeleton.lua
 create mode 100644 game/modules/boot/data/general/npcs/troll.lua
 create mode 100644 game/modules/boot/data/gfx/npc/armored_skeleton_warrior.png
 create mode 100644 game/modules/boot/data/gfx/npc/canine_dw.png
 create mode 100644 game/modules/boot/data/gfx/npc/canine_fox.png
 create mode 100644 game/modules/boot/data/gfx/npc/canine_gw.png
 create mode 100644 game/modules/boot/data/gfx/npc/canine_w.png
 create mode 100644 game/modules/boot/data/gfx/npc/canine_warg.png
 create mode 100644 game/modules/boot/data/gfx/npc/canine_ww.png
 create mode 100644 game/modules/boot/data/gfx/npc/degenerated_skeleton_warrior.png
 create mode 100644 game/modules/boot/data/gfx/npc/skeleton_mage.png
 create mode 100644 game/modules/boot/data/gfx/npc/skeleton_warrior.png
 create mode 100644 game/modules/boot/data/gfx/npc/troll_c.png
 create mode 100644 game/modules/boot/data/gfx/npc/troll_f.png
 create mode 100644 game/modules/boot/data/gfx/npc/troll_m.png
 create mode 100644 game/modules/boot/data/gfx/npc/troll_mt.png
 create mode 100644 game/modules/boot/data/gfx/npc/troll_s.png
 create mode 100644 game/modules/boot/data/gfx/particles/acid.lua
 create mode 100644 game/modules/boot/data/gfx/particles/bolt_fire.lua
 create mode 100644 game/modules/boot/data/gfx/particles/fireflash.lua
 create mode 100644 game/modules/boot/data/gfx/particles/firetrail.lua
 create mode 100644 game/modules/boot/data/gfx/particles/flame.lua
 create mode 100644 game/modules/boot/data/gfx/particles/golden_shield.lua
 create mode 100644 game/modules/boot/data/gfx/particles/lightning.lua
 create mode 100644 game/modules/boot/data/gfx/particles/mana_beam.lua
 create mode 100644 game/modules/boot/data/gfx/particles/sunburst.lua
 create mode 100644 game/modules/boot/data/gfx/shaders/main_fbo.frag
 create mode 100644 game/modules/boot/data/gfx/shaders/main_fbo.lua
 create mode 100644 game/modules/boot/data/gfx/shaders/water.frag
 create mode 100644 game/modules/boot/data/gfx/shaders/water.lua
 create mode 100644 game/modules/boot/data/gfx/terrain/grass.png
 create mode 100644 game/modules/boot/data/gfx/terrain/grass_flower3.png
 create mode 100644 game/modules/boot/data/gfx/terrain/tree_alpha1.png
 create mode 100644 game/modules/boot/data/gfx/terrain/tree_alpha2.png
 create mode 100644 game/modules/boot/data/gfx/terrain/tree_alpha3.png
 create mode 100644 game/modules/boot/data/gfx/terrain/tree_alpha4.png
 create mode 100644 game/modules/boot/data/gfx/terrain/tree_alpha5.png
 create mode 100644 game/modules/boot/data/gfx/terrain/water_floor.png
 create mode 100644 game/modules/boot/data/gfx/terrain/water_floor_alpha.png
 create mode 100644 game/modules/boot/data/rooms/pilar.lua
 create mode 100644 game/modules/boot/data/rooms/simple.lua
 create mode 100644 game/modules/boot/data/talents.lua
 create mode 100644 game/modules/boot/data/timed_effects.lua
 create mode 100644 game/modules/boot/data/zones/dungeon/grids.lua
 create mode 100644 game/modules/boot/data/zones/dungeon/npcs.lua
 create mode 100644 game/modules/boot/data/zones/dungeon/objects.lua
 create mode 100644 game/modules/boot/data/zones/dungeon/traps.lua
 create mode 100644 game/modules/boot/data/zones/dungeon/zone.lua
 create mode 100644 game/modules/boot/dialogs/LoadGame.lua
 create mode 100644 game/modules/boot/dialogs/MainMenu.lua
 create mode 100644 game/modules/boot/dialogs/NewGame.lua
 create mode 100644 game/modules/boot/dialogs/Profile.lua
 create mode 100644 game/modules/boot/dialogs/ProfileLogin.lua
 create mode 100644 game/modules/boot/init.lua
 create mode 100644 game/modules/boot/load.lua

diff --git a/game/engines/default/engine/Game.lua b/game/engines/default/engine/Game.lua
index 377eee86a1..27fcb2a324 100644
--- a/game/engines/default/engine/Game.lua
+++ b/game/engines/default/engine/Game.lua
@@ -98,14 +98,14 @@ end
 --- Displays the screen
 -- Called by the engine core to redraw the screen every frame
 function _M:display()
+	if self.flyers then
+		self.flyers:display()
+	end
+
 	for i, d in ipairs(self.dialogs) do
 		d:display()
 		d:toScreen(d.display_x, d.display_y)
 	end
-
-	if self.flyers then
-		self.flyers:display()
-	end
 end
 
 --- Returns the player
diff --git a/game/engines/default/engine/Module.lua b/game/engines/default/engine/Module.lua
index 1d1abc19c0..840411b123 100644
--- a/game/engines/default/engine/Module.lua
+++ b/game/engines/default/engine/Module.lua
@@ -33,24 +33,12 @@ function _M:listModules()
 --	print("Search Path: ") for k,e in ipairs(fs.getSearchPath()) do print("*",k,e) end
 
 	for i, short_name in ipairs(fs.list("/modules/")) do
---print("!!", short_name)
-		local dir = "/modules/"..short_name
-		if fs.exists(dir.."/init.lua") then
-			local mod = self:loadDefinition(dir)
+		if short_name ~= "boot" then
+			local mod = self:createModule(short_name)
 			if mod then
 				table.insert(ms, mod)
 				ms[mod.short_name] = mod
 			end
-		elseif short_name:find(".team$") then
-			fs.mount(fs.getRealPath(dir), "/testload", false)
-			if fs.exists("/testload/mod/init.lua") then
-				local mod = self:loadDefinition("/testload", dir)
-				if mod then
-					table.insert(ms, mod)
-					ms[mod.short_name] = mod
-				end
-			end
-			fs.umount(fs.getRealPath(dir))
 		end
 	end
 
@@ -65,6 +53,26 @@ function _M:listModules()
 	return ms
 end
 
+function _M:createModule(short_name)
+	local dir = "/modules/"..short_name
+	if fs.exists(dir.."/init.lua") then
+		local mod = self:loadDefinition(dir)
+		if mod and mod.short_name then
+			return mod
+		end
+	elseif short_name:find(".team$") then
+		fs.mount(fs.getRealPath(dir), "/testload", false)
+		if fs.exists("/testload/mod/init.lua") then
+			local mod = self:loadDefinition("/testload", dir)
+			if mod then
+				table.insert(ms, mod)
+			end
+		end
+		fs.umount(fs.getRealPath(dir))
+		if mod and mod.short_name then return mod end
+	end
+end
+
 --- Get a module definition from the module init.lua file
 function _M:loadDefinition(dir, team)
 	local mod_def = loadfile(team and (dir.."/mod/init.lua") or (dir.."/init.lua"))
@@ -140,10 +148,15 @@ end
 -- @param mod the module definition as given by Module:loadDefinition()
 -- @param name the savefile name
 -- @param new_game true if the game must be created (aka new character)
-function _M:instanciate(mod, name, new_game)
-	local popup = Dialog:simplePopup("Loading module", "Please wait while loading the game module...", nil, true)
-	popup.__showup = nil
-	core.display.forceRedraw()
+function _M:instanciate(mod, name, new_game, no_reboot)
+	if not no_reboot then
+		local popup = Dialog:simplePopup("Loading module", "Please wait while loading "..mod.long_name.."...", nil, true)
+		popup.__showup = nil
+		core.display.forceRedraw()
+
+		util.showMainMenu(false, "te4", "LATEST", mod.short_name, name, new_game)
+		return
+	end
 
 	profile.generic.modules_loaded = profile.generic.modules_loaded or {}
 	profile.generic.modules_loaded[mod.short_name] = (profile.generic.modules_loaded[mod.short_name] or 0) + 1
diff --git a/game/engines/default/engine/dialogs/VideoOptions.lua b/game/engines/default/engine/dialogs/VideoOptions.lua
index 68562bf4b1..f0c9c065a1 100644
--- a/game/engines/default/engine/dialogs/VideoOptions.lua
+++ b/game/engines/default/engine/dialogs/VideoOptions.lua
@@ -69,6 +69,15 @@ function _M:generateList()
 		game:registerDialog(menu)
 	end,}
 
+	local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text="Controls the particle effects density.\nThis option allows to change the density of the many particle effects in the game.\nIf the game is slow when displaying spell effects try to lower this setting.#WHITE#"}
+	list[#list+1] = { zone=zone, name="Particle effects density", status=function(item)
+		return tostring(config.settings.particles_density and "enabled" or "disabled")
+	end, fct=function(item)
+
+		game:saveSettings("particles_density", ("particles_density = %s\n"):format(tostring(config.settings.particles_density)))
+		self.c_list:drawItem(item)
+	end,}
+
 	local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text="Activates antialiased texts.\nTexts will look nicer but it can be slower on some computers.\n\n#LIGHT_RED#You must restart the game for it to take effect.#WHITE#"}
 	list[#list+1] = { zone=zone, name="Antialiased texts", status=function(item)
 		return tostring(core.display.getTextBlended() and "enabled" or "disabled")
diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua
index 173d137543..1a6bae5af7 100644
--- a/game/engines/default/engine/utils.lua
+++ b/game/engines/default/engine/utils.lua
@@ -533,7 +533,7 @@ function util.findFreeGrid(sx, sy, radius, block, what)
 	return gs[1][1], gs[1][2]
 end
 
-function util.showMainMenu(no_reboot)
+function util.showMainMenu(no_reboot, reboot_engine, reboot_engine_version, reboot_module, reboot_name, reboot_new)
 	-- Turn based by default
 	core.game.setRealtime(0)
 
@@ -550,14 +550,13 @@ function util.showMainMenu(no_reboot)
 	if game and type(game) == "table" then game:joinThreads(30) end
 
 	if no_reboot then
-		local Menu = require("special.mainmenu.class.Game")
---		local Menu = require("special.mainmenu.class.TestUI")
-		game = Menu.new()
-		game:run()
+		local Module = require("engine.Module")
+		local mod = Module:createModule(__load_module)
+		Module:instanciate(mod, __player_name, __player_new, true)
 	else
 		-- Tell the C engine to discard the current lua state and make a new one
-		print("[MAIN] rebooting lua state")
-		core.game.reboot()
+		print("[MAIN] rebooting lua state: ", reboot_engine, reboot_engine_version, reboot_module, reboot_name, reboot_new)
+		core.game.reboot(reboot_engine or "te4", reboot_engine_version or "LATEST", reboot_module or "boot", reboot_name or "player", reboot_new)
 	end
 end
 
diff --git a/game/engines/default/engine/version.lua b/game/engines/default/engine/version.lua
index 55236756bd..fceb3f17b8 100644
--- a/game/engines/default/engine/version.lua
+++ b/game/engines/default/engine/version.lua
@@ -18,7 +18,7 @@
 -- darkgod@te4.org
 
 -- Engine Version
-engine.version = {0,9,12,"te4",4}
+engine.version = {0,9,13,"te4",4}
 engine.require_c_core = engine.version[5]
 engine.version_id = ("%s-%d_%d.%d.%d"):format(engine.version[4], engine.require_c_core, engine.version[1], engine.version[2], engine.version[3])
 
diff --git a/game/loader/init.lua b/game/loader/init.lua
index f91165821e..1dba2c50a0 100644
--- a/game/loader/init.lua
+++ b/game/loader/init.lua
@@ -25,6 +25,11 @@ fs.mount(homepath, "/")
 local args = {...}
 local req_engine = args[1] or "te4"
 local req_version = args[2] or "LATEST"
+__load_module = args[3] or "boot"
+__player_name = args[4] or "player"
+__player_new = args[5] and true or false
+
+print("Reboot using", req_engine, req_version, __load_module, __player_name, __player_new)
 
 local engines = {}
 
diff --git a/game/modules/boot/ai/player.lua b/game/modules/boot/ai/player.lua
new file mode 100644
index 0000000000..796b743eec
--- /dev/null
+++ b/game/modules/boot/ai/player.lua
@@ -0,0 +1,58 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+local Astar = require "engine.Astar"
+
+-- AI for the escort quest
+-- the NPC will run toward the portal, if hostiles are in sight he attacks them
+newAI("player_demo", function(self)
+	if self:runAI("target_simple") then
+		-- One in "talent_in" chance of using a talent
+		if rng.chance(self.ai_state.talent_in or 6) and self:reactionToward(self.ai_target.actor) < 0 then
+			self:runAI("dumb_talented")
+		end
+		if not self.energy.used then
+			self:runAI("move_simple")
+		end
+		return true
+	else
+		self:runAI("move_player")
+	end
+end)
+
+newAI("move_player", function(self)
+	if self.player_waypoint then
+		local path = self.player_waypoint
+		if not path[1] then
+			self.player_waypoint = nil
+			return self:runAI("move_simple")
+		else
+			local ret = self:move(path[1].x, path[1].y)
+			table.remove(path, 1)
+			return ret
+		end
+	else
+		local e = rng.table(game.level.e_array)
+		while e == self do e = rng.table(game.level.e_array) end
+		print("Selecting waypoint", e.x, e.y, "::", e.name)
+
+		local a = Astar.new(game.level.map, self)
+		self.player_waypoint = a:calc(self.x, self.y, e.x, e.y)
+	end
+end)
diff --git a/game/modules/boot/class/Actor.lua b/game/modules/boot/class/Actor.lua
new file mode 100644
index 0000000000..324efdd90d
--- /dev/null
+++ b/game/modules/boot/class/Actor.lua
@@ -0,0 +1,179 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+require "engine.class"
+require "engine.Actor"
+require "engine.Autolevel"
+require "engine.interface.ActorTemporaryEffects"
+require "engine.interface.ActorLife"
+require "engine.interface.ActorProject"
+require "engine.interface.ActorLevel"
+require "engine.interface.ActorStats"
+require "engine.interface.ActorTalents"
+require "engine.interface.ActorFOV"
+require "mod.class.interface.Combat"
+local Map = require "engine.Map"
+
+module(..., package.seeall, class.inherit(
+	engine.Actor,
+	engine.interface.ActorTemporaryEffects,
+	engine.interface.ActorLife,
+	engine.interface.ActorProject,
+	engine.interface.ActorLevel,
+	engine.interface.ActorStats,
+	engine.interface.ActorTalents,
+	engine.interface.ActorFOV,
+	mod.class.interface.Combat
+))
+
+function _M:init(t, no_default)
+	-- Define some basic combat stats
+	self.combat_armor = 0
+
+	-- Default regen
+	t.life_regen = t.life_regen or 0.25 -- Life regen real slow
+
+	-- Default melee barehanded damage
+	self.combat = { dam=1 }
+
+	engine.Actor.init(self, t, no_default)
+	engine.interface.ActorTemporaryEffects.init(self, t)
+	engine.interface.ActorLife.init(self, t)
+	engine.interface.ActorProject.init(self, t)
+	engine.interface.ActorTalents.init(self, t)
+	engine.interface.ActorStats.init(self, t)
+	engine.interface.ActorLevel.init(self, t)
+	engine.interface.ActorFOV.init(self, t)
+end
+
+function _M:act()
+	if not engine.Actor.act(self) then return end
+
+	self.changed = true
+
+	-- Cooldown talents
+	self:cooldownTalents()
+	-- Regen resources
+	self:regenLife()
+	-- 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
+
+function _M:move(x, y, force)
+	local moved = false
+	if force or self:enoughEnergy() then
+		moved = engine.Actor.move(self, x, y, force)
+		if not force and moved and not self.did_energy then self:useEnergy() end
+	end
+	self.did_energy = nil
+	return moved
+end
+
+function _M:onTakeHit(value, src)
+	return value
+end
+
+function _M:die(src)
+	engine.interface.ActorLife.die(self, src)
+
+	-- Gives the killer some exp for the kill
+	if src and src.gainExp then
+		src:gainExp(self:worthExp(src))
+	end
+
+	-- Spawn an other one somewhere
+	local gen = game.zone:getGenerator("actor", game.level)
+	gen:generateOne()
+
+	return true
+end
+
+function _M:levelup()
+	self.max_life = self.max_life + 2
+
+	-- Healp up on new level
+	self.life = self.max_life
+end
+
+--- Notifies a change of stat value
+function _M:onStatChange(stat, v)
+	if stat == self.STAT_CON then
+		self.max_life = self.max_life + 2
+	end
+end
+
+function _M:attack(target)
+	self:bumpInto(target)
+end
+
+--- Called before a talent is used
+-- Check the actor can cast it
+-- @param ab the talent (not the id, the table)
+-- @return true to continue, false to stop
+function _M:preUseTalent(ab, silent)
+	if not self:enoughEnergy() then return false end
+	return true
+end
+
+--- Called before a talent is used
+-- Check if it must use a turn, mana, stamina, ...
+-- @param ab the talent (not the id, the table)
+-- @param ret the return of the talent action
+-- @return true to continue, false to stop
+function _M:postUseTalent(ab, ret)
+	if not ret then return end
+
+	self:useEnergy()
+	return true
+end
+
+--- How much experience is this actor worth
+-- @param target to whom is the exp rewarded
+-- @return the experience rewarded
+function _M:worthExp(target)
+	return 1
+end
+
+--- Can the actor see the target actor
+-- This does not check LOS or such, only the actual ability to see it.<br/>
+-- Check for telepathy, invisibility, stealth, ...
+function _M:canSee(actor, def, def_pct)
+	if not actor then return false, 0 end
+
+	return true, 100
+end
+
+--- Can the target be applied some effects
+-- @param what a string describing what is being tried
+function _M:canBe(what)
+	if what == "poison" and rng.percent(100 * (self:attr("poison_immune") or 0)) then return false end
+	if what == "cut" and rng.percent(100 * (self:attr("cut_immune") or 0)) then return false end
+	if what == "confusion" and rng.percent(100 * (self:attr("confusion_immune") or 0)) then return false end
+	if what == "blind" and rng.percent(100 * (self:attr("blind_immune") or 0)) then return false end
+	if what == "stun" and rng.percent(100 * (self:attr("stun_immune") or 0)) then return false end
+	if what == "fear" and rng.percent(100 * (self:attr("fear_immune") or 0)) then return false end
+	if what == "knockback" and rng.percent(100 * (self:attr("knockback_immune") or 0)) then return false end
+	if what == "instakill" and rng.percent(100 * (self:attr("instakill_immune") or 0)) then return false end
+	return true
+end
diff --git a/game/modules/boot/class/Game.lua b/game/modules/boot/class/Game.lua
new file mode 100644
index 0000000000..36ba9a88a0
--- /dev/null
+++ b/game/modules/boot/class/Game.lua
@@ -0,0 +1,469 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+require "engine.class"
+require "engine.GameEnergyBased"
+require "engine.interface.GameSound"
+require "engine.interface.GameMusic"
+require "engine.interface.GameTargeting"
+require "engine.KeyBind"
+
+local Module = require "engine.Module"
+local Dialog = require "engine.ui.Dialog"
+local Tooltip = require "engine.Tooltip"
+local MainMenu = require "mod.dialogs.MainMenu"
+
+local Shader = require "engine.Shader"
+local Zone = require "engine.Zone"
+local Map = require "engine.Map"
+local Level = require "engine.Level"
+local FlyingText = require "engine.FlyingText"
+
+local Grid = require "mod.class.Grid"
+local Actor = require "mod.class.Actor"
+local Player = require "mod.class.Player"
+local NPC = require "mod.class.NPC"
+
+module(..., package.seeall, class.inherit(engine.GameEnergyBased, engine.interface.GameMusic, engine.interface.GameSound))
+
+function _M:init()
+	engine.interface.GameMusic.init(self)
+	engine.interface.GameSound.init(self)
+	engine.GameEnergyBased.init(self, engine.KeyBind.new(), 100, 100)
+	self.profile_font = core.display.newFont("/data/font/VeraIt.ttf", 14)
+
+	self.tooltip = Tooltip.new(nil, 14, nil, colors.DARK_GREY, 400)
+
+	self.refuse_threads = true
+	self.normal_key = self.key
+
+	self:loaded()
+end
+
+function _M:loaded()
+	engine.GameEnergyBased.loaded(self)
+	engine.interface.GameMusic.loaded(self)
+	engine.interface.GameSound.loaded(self)
+end
+
+function _M:run()
+	self.flyers = FlyingText.new()
+	self:setFlyingText(self.flyers)
+	self.log = function(style, ...) end
+	self.logSeen = function(e, style, ...) end
+	self.logPlayer = function(e, style, ...) end
+
+	-- Starting from here we create a new game
+	self:newGame()
+
+	-- Ok everything is good to go, activate the game in the engine!
+	self:setCurrent()
+
+	self.mod_list = Module:listModules()
+	self.save_list = Module:listSavefiles()
+
+	self:checkLogged()
+	self:engineVersion()
+
+	-- Setup display
+	self:registerDialog(MainMenu.new())
+
+	-- Run the current music if any
+	self:volumeMusic(config.settings.music.volume)
+	self:playMusic("The saga begins.ogg")
+
+	-- Get news
+	if not self.news then
+		self.news = profile:getNews()
+
+		if self.news then
+			local f = loadstring(self.news.text)
+			if f then
+				local env = {}
+				setfenv(f, env)
+				pcall(f)
+				if env.text and env.version then
+					self.news.text = env.text
+					print("Latest engine version available: ", env.version[4], env.version[1], env.version[2], env.version[3])
+					self.latest_engine_version = env.version
+					if env.link then self.news.link = env.link end
+				else
+					self.news = nil
+				end
+			end
+		end
+
+		if not self.news then
+			self.news = {
+				title = 'Welcome to T-Engine and the Tales of Middle-earth',
+				text = [[From this interface you can create new characters for the game modules you want to play.
+
+#GOLD#"Tales of Middle-earth"#WHITE# is the default game module, you can also install more by selecting "Install a game module" or by going to http://te4.org/
+
+When inside a module remember you can press Escape to bring up a menu to change keybindings, resolution and other module specific options.
+
+Remember that in most roguelikes death is usually permanent so be careful!
+
+Now go and have some fun!]]
+			}
+		end
+
+		if self.news.link then
+			self.tooltip:set("#AQUAMARINE#%s#WHITE#\n---\n%s\n---\n#LIGHT_BLUE##{underline}#%s#LAST##{normal}#", self.news.title, self.news.text, self.news.link)
+		else
+			self.tooltip:set("#AQUAMARINE#%s#WHITE#\n---\n%s", self.news.title, self.news.text)
+		end
+	end
+
+--	self:installNewEngine()
+
+	if not self.firstrunchecked then
+		-- Check first time run for online profile
+		self.firstrunchecked = true
+		self:checkFirstTime()
+	end
+
+	if self.s_log then
+		local w, h = self.s_log:getSize()
+		self.mouse:registerZone(self.w - w, self.h - h, w, h, function(button)
+			if button == "left" then util.browserOpenUrl(self.logged_url) end
+		end, {button=true})
+	end
+
+	if self.news.link then
+		self.mouse:registerZone(5, self.tooltip.h - 30, self.tooltip.w, 30, function(button)
+			if button == "left" then util.browserOpenUrl(self.news.link) end
+		end, {button=true})
+	end
+end
+
+function _M:checkLogged()
+	if profile.auth then
+		self.logged_url = "http://te4.org/players/"..profile.auth.page
+		local str = "Online Profile: "..profile.auth.name.."[#LIGHT_BLUE##{underline}#"..self.logged_url.."#LAST##{normal}#]"
+		local plain = str:removeColorCodes()
+		local w, h = self.profile_font:size(plain)
+		self.s_log = core.display.newSurface(w, h)
+		self.s_log:erase(0, 0, 0)
+		self.s_log:drawColorStringBlended(self.profile_font, str, 0, 0, 255, 255, 0)
+	else
+		self.logged_url = nil
+		self.s_log = nil
+	end
+end
+
+function _M:engineVersion()
+	self.s_version = core.display.drawStringBlendedNewSurface(self.profile_font, ("T-Engine4 version: %d.%d.%d"):format(engine.version[1], engine.version[2], engine.version[3]), 185, 225, 0)
+end
+
+function _M:newGame()
+	self.player = Player.new{name=self.player_name, game_ender=true}
+	Map:setViewerActor(self.player)
+	self:setupDisplayMode()
+
+	self.player:resolve()
+	self.player:resolve(nil, true)
+	self.player.energy.value = self.energy_to_act
+
+	Zone:setup{npc_class="mod.class.NPC", grid_class="mod.class.Grid", }
+	self:changeLevel(1, "dungeon")
+end
+
+function _M:onResolutionChange()
+	engine.Game.onResolutionChange(self)
+	print("[RESOLUTION] changed to ", self.w, self.h)
+	self:setupDisplayMode()
+end
+
+function _M:setupDisplayMode()
+	Map:setViewPort(0, 0, self.w, self.h, 32, 32, nil, 22, true, true)
+	Map:resetTiles()
+	Map.tiles.use_images = true
+
+	-- Create the framebuffer
+	self.fbo = core.display.newFBO(game.w, game.h)
+	if self.fbo then
+		self.fbo_shader = Shader.new("main_fbo")
+		if not self.fbo_shader.shad then
+			self.fbo = nil self.fbo_shader = nil
+		else
+			self.fbo_shader:setUniform("colorize", {1,1,1})
+		end
+	end
+end
+
+function _M:changeLevel(lev, zone)
+	local old_lev = (self.level and not zone) and self.level.level or -1000
+	if zone then
+		if self.zone then
+			self.zone:leaveLevel(false, lev, old_lev)
+			self.zone:leave()
+		end
+		if type(zone) == "string" then
+			self.zone = Zone.new(zone)
+		else
+			self.zone = zone
+		end
+	end
+	self.zone:getLevel(self, lev, old_lev)
+
+	if lev > old_lev then
+		self.player:move(self.level.default_up.x, self.level.default_up.y, true)
+	else
+		self.player:move(self.level.default_down.x, self.level.default_down.y, true)
+	end
+	self.level:addEntity(self.player)
+end
+
+function _M:getPlayer()
+	return self.player
+end
+
+function _M:tick()
+	if self.level then
+		engine.GameEnergyBased.tick(self)
+		-- Fun stuff: this can make the game realtime, although callit it in display() will make it work better
+		-- (since display is on a set FPS while tick() ticks as much as possible
+		-- engine.GameEnergyBased.tick(self)
+	end
+	return false
+end
+
+--- Called every game turns
+-- Does nothing, you can override it
+function _M:onTurn()
+	-- The following happens only every 10 game turns (once for every turn of 1 mod speed actors)
+	if self.turn % 10 ~= 0 then return end
+
+	-- Process overlay effects
+	self.level.map:processEffects()
+end
+
+function _M:display()
+	-- Display using Framebuffer, so that we can use shaders and all
+	if self.fbo then self.fbo:use(true) end
+
+	-- Now the map, if any
+	if self.level and self.level.map and self.level.map.finished then
+		-- Display the map and compute FOV for the player if needed
+		if self.level.map.changed then
+			self.player:playerFOV()
+		end
+
+		self.level.map:display()
+	end
+
+	-- Draw it here, inside the FBO
+	self.flyers:display()
+
+	-- Display using Framebuffer, sotaht we can use shaders and all
+	if self.fbo then
+		self.fbo:use(false)
+		_2DNoise:bind(1, false)
+		self.fbo:toScreen(
+			self.level.map.display_x, self.level.map.display_y,
+			self.level.map.viewport.width, self.level.map.viewport.height,
+			self.fbo_shader.shad
+		)
+	else
+--		core.display.drawQuad(0, 0, game.w, game.h, 128, 128, 128, 128)
+	end
+
+	if self.s_log then
+		local w, h = self.s_log:getSize()
+		self.s_log:toScreen(self.w - w, self.h - h)
+	end
+--	local w, h = self.s_version:getSize()
+--	self.s_version:toScreen(0, self.h - h)
+
+	self.tooltip:display()
+	self.tooltip:toScreen(5, 5)
+
+	local old = self.flyers
+	self.flyers = nil
+	engine.GameEnergyBased.display(self)
+	self.flyers = old
+end
+
+--- Skip to a module directly ?
+function _M:commandLineArgs(args)
+	local req_mod = nil
+	local req_save = nil
+	local req_new = false
+	for i, arg in ipairs(args) do
+		if arg:find("^%-M") then
+			-- Force module loading
+			req_mod = arg:sub(3)
+		end
+		if arg:find("^%-u") then
+			-- Force save loading
+			req_save = arg:sub(3)
+		end
+		if arg:find("^%-n") then
+			-- Force save loading
+			req_new = true
+		end
+	end
+
+	if req_mod then
+		local mod = self.mod_list[req_mod]
+		if mod then
+			Module:instanciate(mod, req_save or "player", req_new)
+		else
+			print("Error: module "..req_mod.." not found!")
+		end
+	end
+end
+
+--- Ask if we realy want to close, if so, save the game first
+function _M:onQuit()
+	if self.is_quitting then return end
+	self.is_quitting = Dialog:yesnoPopup("Quit", "Really exit T-Engine/ToME?", function(ok)
+		self.is_quitting = false
+		if ok then os.exit() end
+	end, "Quit", "Continue")
+end
+
+profile_help_text = [[#LIGHT_GREEN#T-Engine4#LAST# allows you to sync your player profile with the website #LIGHT_BLUE#http://te4.org/#LAST#
+
+This allows you to:
+* Play from several computers without having to copy unlocks and achievements.
+* Keep track of your modules progression, kill count, ...
+* Cool statistics for each module to help sharpen your gameplay style
+* Help the game developers balance and refine the game
+
+Later on you will have an online profile page you can show to people to brag.
+This is all optional, you are not forced to use this feature at all, but the developers would thank you if you did as it will
+make balancing easier.
+Online profile requires an internet connection, if not available it will wait and sync when it finds one.]]
+
+function _M:checkFirstTime()
+	if not profile.generic.firstrun then
+		profile:checkFirstRun()
+		local text = "Thanks for downloading T-Engine/ToME.\n\n"..profile_help_text
+		Dialog:yesnoLongPopup("Welcome to T-Engine", text, 400, function(ret)
+			if ret then
+				self:registerDialog(require("mod.dialogs.Profile").new())
+			end
+		end, "Register now", "Maybe later")
+	end
+end
+
+function _M:selectStepInstall()
+	local linda, th = Module:loadRemoteList()
+	local rawdllist = linda:receive("moduleslist")
+	th:join()
+
+	local dllist = {}
+	for i, mod in ipairs(rawdllist) do
+		if not self.mod_list[mod.short_name] then
+			dllist[#dllist+1] = mod
+		else
+			local lmod = self.mod_list[mod.short_name]
+			if mod.version[1] * 1000000 + mod.version[2] * 1000 + mod.version[3] > lmod.version[1] * 1000000 + lmod.version[2] * 1000 + lmod.version[3] then
+				dllist[#dllist+1] = mod
+			end
+		end
+	end
+
+	if #dllist == 0 then
+		Dialog:simplePopup("No modules available", "There are no modules to install or upgrade.")
+		return
+	end
+
+	local display_module = Dialog.new("", self.w * 0.73, self.h, self.w * 0.26, 0, 255)
+
+	for i, mod in ipairs(dllist) do
+		mod.fct = function()
+			local d = DownloadDialog.new("Downloading: "..mod.long_name, mod.download, function(di, data)
+				fs.mkdir("/modules")
+				local f = fs.open("/modules/"..mod.short_name..".team", "w")
+				for i, v in ipairs(data) do f:write(v) end
+				f:close()
+
+				-- Relist modules and savefiles
+				self.mod_list = Module:listModules()
+				self.save_list = Module:listSavefiles()
+
+				if self.mod_list[mod.short_name] then
+					Dialog:simplePopup("Success!", "Your new game is now installed, you can play!", function() self:unregisterDialog(display_module) self:selectStepMain() end)
+				else
+					Dialog:simplePopup("Error!", "The downloaded game does not seem to respond to the test. Please contact contact@te4.org")
+				end
+			end)
+			self:registerDialog(d)
+			d:startDownload()
+		end
+		mod.onSelect = function()
+			display_module.title = mod.long_name
+			display_module.changed = true
+		end
+	end
+
+	display_module.drawDialog = function(self, s)
+		local lines = dllist[game.step.selected].description:splitLines(self.w - 8, self.font)
+		local r, g, b
+		for i = 1, #lines do
+			r, g, b = s:drawColorStringBlended(self.font, lines[i], 0, i * self.font:lineSkip(), r, g, b)
+		end
+	end
+	self:registerDialog(display_module)
+
+	self.step = ButtonList.new(dllist, 10, 10, self.w * 0.24, (5 + 35) * #dllist, nil, 5)
+	self.step:setKeyHandling()
+	self.step:setMouseHandling()
+	self.step.key:addBind("EXIT", function() self:unregisterDialog(display_module) self:selectStepMain() end)
+end
+
+function _M:createProfile(loginItem)
+	if self.justlogin then
+		profile:performlogin(loginItem.login, loginItem.pass)
+		if profile.auth then
+			Dialog:simplePopup("Profile logged in!", "Your online profile is active now...", function() self:checkLogged() self:selectStepProfile() end )
+		else
+			Dialog:simplePopup("Log in rejected", "Couldn't log you...", function() self:selectStepProfile() end )
+		end
+		return
+	end
+	profile:newProfile(loginItem.login, loginItem.name, loginItem.pass, loginItem.email)
+	if (profile.auth) then
+		Dialog:simplePopup("Profile created!", "Your online profile is active now...", function() self:checkLogged() end )
+	else
+		Dialog:simplePopup("Profile Failed to authenticate!", "Try logging in in a few moments", function() end )
+	end
+
+end
+
+function _M:installNewEngine()
+	if not self.latest_engine_version then return end
+	print("te4.org told us latest engine is", self.latest_engine_version[4], self.latest_engine_version[5], self.latest_engine_version[1], self.latest_engine_version[2], self.latest_engine_version[3])
+	if engine.version_check(self.latest_engine_version) == "newer" then
+		local url = ("http://te4.org/dl/engines/%s_%d:%d.%d.%d.teae"):format(self.latest_engine_version[4], self.latest_engine_version[5], self.latest_engine_version[1], self.latest_engine_version[2], self.latest_engine_version[3])
+		local d = DownloadDialog.new(("Downloading: T-Engine 4 %d.%d.%d"):format(self.latest_engine_version[1], self.latest_engine_version[2], self.latest_engine_version[3]), url, function(di, data)
+			fs.mkdir("/engines")
+			local f = fs.open(("/engines/%s-%d_%d.%d.%d.teae"):format(self.latest_engine_version[4], self.latest_engine_version[5], self.latest_engine_version[1], self.latest_engine_version[2], self.latest_engine_version[3]), "w")
+			for i, v in ipairs(data) do f:write(v) end
+			f:close()
+
+			Dialog:simplePopup("Success!", "The new engine is installed, it will now restart using it.", function() util.showMainMenu() end)
+		end)
+		self:registerDialog(d)
+		d:startDownload()
+	end
+end
\ No newline at end of file
diff --git a/game/modules/boot/class/Grid.lua b/game/modules/boot/class/Grid.lua
new file mode 100644
index 0000000000..fcdf9ce2ce
--- /dev/null
+++ b/game/modules/boot/class/Grid.lua
@@ -0,0 +1,107 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+require "engine.class"
+require "engine.Grid"
+local DamageType = require "engine.DamageType"
+
+module(..., package.seeall, class.inherit(engine.Grid))
+
+function _M:init(t, no_default)
+	engine.Grid.init(self, t, no_default)
+end
+
+function _M:block_move(x, y, e, act, couldpass)
+	-- Open doors
+	if self.door_opened and act then
+		game.level.map(x, y, engine.Map.TERRAIN, game.zone.grid_list.DOOR_OPEN)
+		return true
+	elseif self.door_opened and not couldpass then
+		return true
+	end
+
+	-- Pass walls
+	if e and self.can_pass and e.can_pass then
+		for what, check in pairs(e.can_pass) do
+			if self.can_pass[what] and self.can_pass[what] <= check then return false end
+		end
+	end
+
+	return self.does_block_move
+end
+
+function _M:on_move(x, y, who, forced)
+	if forced then return end
+	if who.move_project and next(who.move_project) then
+		for typ, dam in pairs(who.move_project) do
+			DamageType:get(typ).projector(who, x, y, typ, dam)
+		end
+	end
+end
+
+--- Generate sub entities to make nice trees
+function _M:makeTrees(base, max)
+	local function makeTree(nb, z)
+		local inb = 4 - nb
+		return engine.Entity.new{
+			z = z,
+			display_scale = rng.float(0.5 + inb / 6, 1.3),
+			display_x = rng.range(-engine.Map.tile_w / 3 * nb / 3, engine.Map.tile_w / 3 * nb / 3),
+			display_y = rng.range(-engine.Map.tile_h / 3 * nb / 3, engine.Map.tile_h / 3 * nb / 3),
+			display_on_seen = true,
+			display_on_remember = true,
+			image = (base or "terrain/tree_alpha")..rng.range(1,max or 5)..".png",
+		}
+	end
+
+	local v = rng.range(0, 100)
+	local tbl
+	if v < 33 then
+		tbl = { makeTree(3, 16), makeTree(3, 17), makeTree(3, 18), }
+	elseif v < 66 then
+		tbl = { makeTree(2, 16), makeTree(2, 17), }
+	else
+		tbl = { makeTree(1, 16), }
+	end
+	table.sort(tbl, function(a,b) return a.display_y < b.display_y end)
+	return tbl
+end
+
+--- Generate sub entities to make translucent water
+function _M:makeWater(z, prefix)
+	prefix = prefix or ""
+	return { engine.Entity.new{
+		z = z and 16 or 9,
+		image = "terrain/"..prefix.."water_floor_alpha.png",
+		shader = prefix.."water", textures = { function() return _3DNoise, true end },
+		display_on_seen = true,
+		display_on_remember = true,
+	} }
+end
+
+--- Merge sub entities
+function _M:mergeSubEntities(...)
+	local tbl = {}
+	for i, t in ipairs{...} do if t then
+		for j, e in ipairs(t) do
+			tbl[#tbl+1] = e
+		end
+	end end
+	return tbl
+end
diff --git a/game/modules/boot/class/NPC.lua b/game/modules/boot/class/NPC.lua
new file mode 100644
index 0000000000..f838e97286
--- /dev/null
+++ b/game/modules/boot/class/NPC.lua
@@ -0,0 +1,53 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+require "engine.class"
+local ActorAI = require "engine.interface.ActorAI"
+local Faction = require "engine.Faction"
+require "mod.class.Actor"
+
+module(..., package.seeall, class.inherit(mod.class.Actor, engine.interface.ActorAI))
+
+function _M:init(t, no_default)
+	mod.class.Actor.init(self, t, no_default)
+	ActorAI.init(self, t)
+end
+
+function _M:act()
+	-- Do basic actor stuff
+	if not mod.class.Actor.act(self) then return end
+
+	-- Compute FOV, if needed
+	self:computeFOV(self.sight or 20)
+
+	-- Let the AI think .... beware of Shub !
+	-- If AI did nothing, use energy anyway
+	self:doAI()
+	if not self.energy.used then self:useEnergy() end
+end
+
+--- Called by ActorLife interface
+-- We use it to pass aggression values to the AIs
+function _M:onTakeHit(value, src)
+	if not self.ai_target.actor and src.targetable then
+		self.ai_target.actor = src
+	end
+
+	return mod.class.Actor.onTakeHit(self, value, src)
+end
diff --git a/game/modules/boot/class/Player.lua b/game/modules/boot/class/Player.lua
new file mode 100644
index 0000000000..be09dbff6d
--- /dev/null
+++ b/game/modules/boot/class/Player.lua
@@ -0,0 +1,108 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+require "engine.class"
+require "mod.class.NPC"
+local Map = require "engine.Map"
+local ActorTalents = require "engine.interface.ActorTalents"
+
+--- Defines the player
+-- It is a normal actor, with some redefined methods to handle user interaction.<br/>
+-- It is also able to run and rest and use hotkeys
+module(..., package.seeall, class.inherit(
+	mod.class.NPC
+))
+
+function _M:init(t, no_default)
+	t.display=t.display or '@'
+	t.color_r=t.color_r or 230
+	t.color_g=t.color_g or 230
+	t.color_b=t.color_b or 230
+
+	t.player = true
+	t.type = t.type or "humanoid"
+	t.subtype = t.subtype or "player"
+	t.faction = t.faction or "players"
+
+	t.lite = t.lite or 0
+
+	t.ai = "player_demo"
+	t.ai_state = { talent_in=2, },
+
+	mod.class.NPC.init(self, t, no_default)
+
+	self:learnTalent(self.T_MANATHRUST, true, 2)
+	self:learnTalent(self.T_FLAME, true, 2)
+	self:learnTalent(self.T_FIREFLASH, true, 2)
+	self:learnTalent(self.T_LIGHTNING, true, 2)
+	self:learnTalent(self.T_SUNSHIELD, true, 2)
+end
+
+function _M:move(x, y, force)
+	local moved = mod.class.NPC.move(self, x, y, force)
+	if moved then
+		game.level.map:moveViewSurround(self.x, self.y, 8, 8)
+	end
+	return moved
+end
+
+function _M:act()
+	if not mod.class.NPC.act(self) then return end
+end
+
+-- Precompute FOV form, for speed
+local fovdist = {}
+for i = 0, 30 * 30 do
+	fovdist[i] = math.max((20 - math.sqrt(i)) / 14, 0.6)
+end
+
+function _M:playerFOV()
+	-- Clean FOV before computing it
+	game.level.map:cleanFOV()
+	-- Compute both the normal and the lite FOV, using cache
+	self:computeFOV(self.sight or 20, "block_sight", function(x, y, dx, dy, sqdist)
+		game.level.map:apply(x, y, fovdist[sqdist])
+	end, true, false, true)
+	self:computeFOV(self.lite, "block_sight", function(x, y, dx, dy, sqdist) game.level.map:applyLite(x, y) end, true, true, true)
+end
+
+function _M:onTakeHit(value, src)
+	return 0
+end
+
+function _M:setName(name)
+	self.name = name
+	game.save_name = name
+end
+
+--- Notify the player of available cooldowns
+function _M:onTalentCooledDown(tid)
+	local t = self:getTalentFromId(tid)
+
+	local x, y = game.level.map:getTileToScreen(self.x, self.y)
+	game.flyers:add(x, y, 30, -0.3, -3.5, ("%s available"):format(t.name:capitalize()), {0,255,00})
+	game.log("#00ff00#Talent %s is ready to use.", t.name)
+end
+
+function _M:levelup()
+	mod.class.NPC.levelup(self)
+
+	local x, y = game.level.map:getTileToScreen(self.x, self.y)
+	game.flyers:add(x, y, 80, 0.5, -2, "LEVEL UP!", {0,255,255})
+end
diff --git a/game/modules/boot/class/interface/Combat.lua b/game/modules/boot/class/interface/Combat.lua
new file mode 100644
index 0000000000..3ea59a4439
--- /dev/null
+++ b/game/modules/boot/class/interface/Combat.lua
@@ -0,0 +1,56 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+require "engine.class"
+local DamageType = require "engine.DamageType"
+local Map = require "engine.Map"
+local Target = require "engine.Target"
+local Talents = require "engine.interface.ActorTalents"
+
+--- Interface to add ToME combat system
+module(..., package.seeall, class.make)
+
+--- Checks what to do with the target
+-- Talk ? attack ? displace ?
+function _M:bumpInto(target)
+	local reaction = self:reactionToward(target)
+	if reaction < 0 then
+		return self:attackTarget(target)
+	elseif reaction >= 0 then
+		if self.move_others then
+			-- Displace
+			game.level.map:remove(self.x, self.y, Map.ACTOR)
+			game.level.map:remove(target.x, target.y, Map.ACTOR)
+			game.level.map(self.x, self.y, Map.ACTOR, target)
+			game.level.map(target.x, target.y, Map.ACTOR, self)
+			self.x, self.y, target.x, target.y = target.x, target.y, self.x, self.y
+		end
+	end
+end
+
+--- Makes the death happen!
+function _M:attackTarget(target, mult)
+	if self.combat then
+		local dam = self.combat.dam + self:getStr() - target.combat_armor
+		DamageType:get(DamageType.PHYSICAL).projector(self, target.x, target.y, DamageType.PHYSICAL, math.max(0, dam))
+	end
+
+	-- We use up our own energy
+	self:useEnergy(game.energy_to_act)
+end
diff --git a/game/modules/boot/data/birth/descriptors.lua b/game/modules/boot/data/birth/descriptors.lua
new file mode 100644
index 0000000000..64f6113656
--- /dev/null
+++ b/game/modules/boot/data/birth/descriptors.lua
@@ -0,0 +1,56 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+newBirthDescriptor{
+	type = "base",
+	name = "base",
+	desc = {
+	},
+	experience = 1.0,
+
+	copy = {
+		max_level = 10,
+		lite = 4,
+		max_life = 25,
+	},
+}
+
+newBirthDescriptor{
+	type = "role",
+	name = "Destroyer",
+	desc =
+	{
+		"Crashhhhh!",
+	},
+	talents = {
+		[ActorTalents.T_KICK]=1,
+	},
+}
+
+newBirthDescriptor{
+	type = "role",
+	name = "Acid-maniac",
+	desc =
+	{
+		"Zshhhhhhhh!",
+	},
+	talents = {
+		[ActorTalents.T_ACID_SPRAY]=1,
+	},
+}
diff --git a/game/modules/boot/data/damage_types.lua b/game/modules/boot/data/damage_types.lua
new file mode 100644
index 0000000000..146b89c756
--- /dev/null
+++ b/game/modules/boot/data/damage_types.lua
@@ -0,0 +1,61 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+-- The basic stuff used to damage a grid
+setDefaultProjector(function(src, x, y, type, dam)
+	local target = game.level.map(x, y, Map.ACTOR)
+	if target then
+		if src.player then dam = dam * 6 end
+		local sx, sy = game.level.map:getTileToScreen(x, y)
+		if target:takeHit(dam, src) then
+			if src == game.player or target == game.player then
+				game.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, -3, "Kill!", {255,0,255})
+			end
+		else
+			if src == game.player then
+				game.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, -3, tostring(-math.ceil(dam)), {0,255,0})
+			elseif target == game.player then
+				game.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, -3, tostring(-math.ceil(dam)), {255,0,0})
+			end
+		end
+		return dam
+	end
+	return 0
+end)
+
+newDamageType{
+	name = "physical", type = "PHYSICAL",
+}
+newDamageType{
+	name = "acid", type = "ACID", text_color = "#GREEN#",
+}
+newDamageType{
+	name = "arcane", type = "ARCANE", text_color = "#PURPLE#",
+}
+-- Light damage
+newDamageType{
+	name = "light", type = "LIGHT", text_color = "#YELLOW#",
+}
+-- The elemental damges
+newDamageType{
+	name = "fire", type = "FIRE", text_color = "#LIGHT_RED#",
+}
+newDamageType{
+	name = "lightning", type = "LIGHTNING", text_color = "#ROYAL_BLUE#",
+}
diff --git a/game/modules/boot/data/general/grids/basic.lua b/game/modules/boot/data/general/grids/basic.lua
new file mode 100644
index 0000000000..171745a3c4
--- /dev/null
+++ b/game/modules/boot/data/general/grids/basic.lua
@@ -0,0 +1,83 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+newEntity{
+	define_as = "UP_WILDERNESS",
+	name = "exit to the wilds",
+	display = '<', color_r=255, color_g=0, color_b=255, back_color=colors.DARK_GREY,
+	always_remember = true,
+	notice = true,
+	change_level = 1,
+	change_zone = "wilderness",
+}
+
+newEntity{
+	define_as = "UP",
+	name = "previous level",
+	display = '<', color_r=255, color_g=255, color_b=0, back_color=colors.DARK_GREY,
+	notice = true,
+	always_remember = true,
+	change_level = -1,
+}
+
+newEntity{
+	define_as = "DOWN",
+	name = "next level",
+	display = '>', color_r=255, color_g=255, color_b=0, back_color=colors.DARK_GREY,
+	notice = true,
+	always_remember = true,
+	change_level = 1,
+}
+
+newEntity{
+	define_as = "FLOOR",
+	name = "floor", image = "terrain/marble_floor.png",
+	display = ' ', color_r=255, color_g=255, color_b=255, back_color=colors.DARK_GREY,
+}
+
+newEntity{
+	define_as = "WALL",
+	name = "wall", image = "terrain/granite_wall1.png",
+	display = '#', color_r=255, color_g=255, color_b=255, back_color=colors.GREY,
+	always_remember = true,
+	does_block_move = true,
+	can_pass = {pass_wall=1},
+	block_sight = true,
+	air_level = -20,
+	dig = "FLOOR",
+}
+
+newEntity{
+	define_as = "DOOR",
+	name = "door", image = "terrain/granite_door1.png",
+	display = '+', color_r=238, color_g=154, color_b=77, back_color=colors.DARK_UMBER,
+	notice = true,
+	always_remember = true,
+	block_sight = true,
+	door_opened = "DOOR_OPEN",
+	dig = "DOOR_OPEN",
+}
+
+newEntity{
+	define_as = "DOOR_OPEN",
+	name = "open door", image = "terrain/granite_door1_open.png",
+	display = "'", color_r=238, color_g=154, color_b=77, back_color=colors.DARK_GREY,
+	always_remember = true,
+	door_closed = "DOOR",
+}
diff --git a/game/modules/boot/data/general/grids/forest.lua b/game/modules/boot/data/general/grids/forest.lua
new file mode 100644
index 0000000000..aea5985f38
--- /dev/null
+++ b/game/modules/boot/data/general/grids/forest.lua
@@ -0,0 +1,46 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+newEntity{
+	define_as = "GRASS",
+	name = "grass", image = "terrain/grass.png",
+	display = '.', color=colors.LIGHT_GREEN, back_color={r=44,g=95,b=43},
+}
+
+for i = 1, 20 do
+newEntity{
+	define_as = "TREE"..(i > 1 and i or ""),
+	name = "tree",
+	image = "terrain/grass.png",
+	add_displays = class:makeTrees("terrain/tree_alpha"),
+	display = '#', color=colors.LIGHT_GREEN, back_color={r=44,g=95,b=43},
+	always_remember = true,
+	can_pass = {pass_tree=1},
+	does_block_move = true,
+	block_sight = true,
+	dig = "GRASS",
+}
+end
+
+newEntity{
+	define_as = "FLOWER",
+	name = "flower", image = "terrain/grass_flower3.png",
+	display = ';', color=colors.YELLOW, back_color={r=44,g=95,b=43},
+}
+
diff --git a/game/modules/boot/data/general/grids/water.lua b/game/modules/boot/data/general/grids/water.lua
new file mode 100644
index 0000000000..ab01a738bf
--- /dev/null
+++ b/game/modules/boot/data/general/grids/water.lua
@@ -0,0 +1,40 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+
+------------------------------------------------------------
+-- For outside
+------------------------------------------------------------
+
+newEntity{
+	define_as = "SHALLOW_WATER",
+	name = "shallow water", image = "terrain/water_floor.png",
+	display = '~', color=colors.LIGHT_BLUE, back_color=colors.DARK_BLUE,
+	add_displays = class:makeWater(false),
+	always_remember = true,
+}
+
+newEntity{
+	define_as = "DEEP_WATER",
+	name = "deep water", image = "terrain/water_floor.png",
+	display = '~', color=colors.AQUAMARINE, back_color=colors.DARK_BLUE,
+	add_displays = class:makeWater(true),
+	always_remember = true,
+	air_level = -5, air_condition="water",
+}
diff --git a/game/modules/boot/data/general/npcs/canine.lua b/game/modules/boot/data/general/npcs/canine.lua
new file mode 100644
index 0000000000..3cce1c1d4a
--- /dev/null
+++ b/game/modules/boot/data/general/npcs/canine.lua
@@ -0,0 +1,86 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+-- last updated:  5:11 PM 1/29/2010
+
+newEntity{
+	define_as = "BASE_NPC_CANINE",
+	type = "animal", subtype = "canine",
+	display = "C", color=colors.WHITE,
+	level_range = {1, nil}, exp_worth = 1,
+
+	ai = "dumb_talented_simple", ai_state = { talent_in=2, },
+	energy = { mod=1.1 },
+	combat = { dammod={str=0.6} },
+	combat_armor = 1, combat_def = 1,
+}
+
+newEntity{ base = "BASE_NPC_CANINE",
+	name = "wolf", color=colors.UMBER, image="npc/canine_w.png",
+	desc = [[Lean, mean, and shaggy, it stares at you with hungry eyes.]],
+	rarity = 1,
+	max_life = resolvers.rngavg(40,70),
+	combat_armor = 1, combat_def = 3,
+	combat = { dam=5, atk=15, apr=3 },
+}
+
+newEntity{ base = "BASE_NPC_CANINE",
+	name = "great wolf", color=colors.UMBER, image="npc/canine_gw.png",
+	desc = [[Larger than a normal wolf, it prowls and snaps at you.]],
+	rarity = 3,
+	max_life = resolvers.rngavg(60,90),
+	combat_armor =2, combat_def = 4,
+	combat = { dam=6, atk=15, apr=3 },
+}
+
+newEntity{ base = "BASE_NPC_CANINE",
+	name = "dire wolf", color=colors.DARK_UMBER, image="npc/canine_dw.png",
+	desc = [[Easily as big as a horse, this wolf menaces you with its claws and fangs.]],
+	rarity = 3,
+	max_life = resolvers.rngavg(80,110),
+	combat_armor = 3, combat_def = 5,
+	combat = { dam=9, atk=15, apr=4 },
+}
+
+newEntity{ base = "BASE_NPC_CANINE",
+	name = "white wolf", color=colors.WHITE, image="npc/canine_ww.png",
+	desc = [[A large and muscled wolf from the northern wastes. Its breath is cold and icy and its fur coated in frost.]],
+	rarity = 3,
+	max_life = resolvers.rngavg(70,100),
+	combat_armor = 3, combat_def = 4,
+	combat = { dam=8, atk=15, apr=3 },
+}
+
+newEntity{ base = "BASE_NPC_CANINE",
+	name = "warg", color=colors.BLACK, image="npc/canine_warg.png",
+	desc = [[It is a large wolf with eyes full of cunning.]],
+	rarity = 4,
+	max_life = resolvers.rngavg(60,100),
+	combat_armor = 5, combat_def = 7,
+	combat = { dam=10, atk=17, apr=5 },
+}
+
+newEntity{ base = "BASE_NPC_CANINE",
+	name = "fox", color=colors.RED, image="npc/canine_fox.png",
+	desc = [[The quick brown fox jumps over the lazy dog.]],
+	rarity = 3,
+	max_life = resolvers.rngavg(40,50),
+	combat_armor = 1, combat_def = 3,
+	combat = { dam=4, atk=10, apr=3 },
+}
diff --git a/game/modules/boot/data/general/npcs/skeleton.lua b/game/modules/boot/data/general/npcs/skeleton.lua
new file mode 100644
index 0000000000..8ab706971c
--- /dev/null
+++ b/game/modules/boot/data/general/npcs/skeleton.lua
@@ -0,0 +1,72 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+local Talents = require("engine.interface.ActorTalents")
+
+newEntity{
+	define_as = "BASE_NPC_SKELETON",
+	type = "undead", subtype = "skeleton",
+	display = "s", color=colors.WHITE,
+	level_range = {1, nil}, exp_worth = 1,
+
+	combat = { dam=1, atk=1, apr=1 },
+
+	ai = "dumb_talented_simple", ai_state = { talent_in=1, },
+	energy = { mod=1 },
+
+	open_door = true,
+
+	blind_immune = 1,
+	fear_immune = 1,
+	see_invisible = 2,
+	undead = 1,
+}
+
+newEntity{ base = "BASE_NPC_SKELETON",
+	name = "degenerated skeleton warrior", color=colors.WHITE, image="npc/degenerated_skeleton_warrior.png",
+	rarity = 1,
+	max_life = resolvers.rngavg(40,50),
+	combat_armor = 5, combat_def = 1,
+}
+
+newEntity{ base = "BASE_NPC_SKELETON",
+	name = "skeleton warrior", color=colors.SLATE, image="npc/skeleton_warrior.png",
+	rarity = 1,
+	max_life = resolvers.rngavg(90,100),
+	combat_armor = 5, combat_def = 1,
+	ai_state = { talent_in=1, },
+}
+
+newEntity{ base = "BASE_NPC_SKELETON",
+	name = "skeleton mage", color=colors.LIGHT_RED, image="npc/skeleton_mage.png",
+	rarity = 3,
+	max_life = resolvers.rngavg(50,60),
+	max_mana = resolvers.rngavg(70,80),
+	combat_armor = 3, combat_def = 1,
+	stats = { str=10, dex=12, cun=14, mag=14, con=10 },
+	resolvers.talents{ [Talents.T_FLAME]=2, [Talents.T_MANATHRUST]=3 },
+}
+
+newEntity{ base = "BASE_NPC_SKELETON",
+	name = "armoured skeleton warrior", color=colors.STEEL_BLUE,
+	level_range = {10, nil}, exp_worth = 1,
+	rarity = 5,
+	max_life = resolvers.rngavg(90,100),
+	combat_armor = 5, combat_def = 1,
+}
diff --git a/game/modules/boot/data/general/npcs/troll.lua b/game/modules/boot/data/general/npcs/troll.lua
new file mode 100644
index 0000000000..21634632fd
--- /dev/null
+++ b/game/modules/boot/data/general/npcs/troll.lua
@@ -0,0 +1,77 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+local Talents = require("engine.interface.ActorTalents")
+
+newEntity{
+	define_as = "BASE_NPC_TROLL",
+	type = "giant", subtype = "troll",
+	display = "T", color=colors.UMBER,
+	level_range = {1, nil}, exp_worth = 1,
+
+	ai = "dumb_talented_simple", ai_state = { talent_in=1, },
+	energy = { mod=1 },
+
+	open_door = true,
+	fear_immune = 1,
+}
+
+newEntity{ base = "BASE_NPC_TROLL",
+	name = "forest troll", color=colors.YELLOW_GREEN, image="npc/troll_f.png",
+	desc = [[Green-skinned and ugly, this massive humanoid glares at you, clenching wart-covered green fists.]],
+	rarity = 1,
+	max_life = resolvers.rngavg(100,120),
+	combat_armor = 4, combat_def = 0,
+}
+
+newEntity{ base = "BASE_NPC_TROLL",
+	name = "stone troll", color=colors.DARK_SLATE_GRAY, image="npc/troll_s.png",
+	desc = [[A giant troll with scabrous black skin. With a shudder, you notice the belt of dwarf skulls around his massive waist.]],
+	rarity = 1,
+	max_life = resolvers.rngavg(120,140),
+	combat_armor = 7, combat_def = 0,
+}
+
+newEntity{ base = "BASE_NPC_TROLL",
+	name = "cave troll", color=colors.SLATE, image="npc/troll_c.png",
+	desc = [[This huge troll wields a massive spear and has a disturbingly intelligent look in its piggy eyes.]],
+	rarity = 2,
+	max_life = resolvers.rngavg(120,140),
+	combat_armor = 9, combat_def = 3,
+}
+
+newEntity{ base = "BASE_NPC_TROLL",
+	name = "mountain troll", color=colors.UMBER, image="npc/troll_m.png",
+	desc = [[A large and athletic troll with an extremely tough and warty hide.]],
+	rarity = 3,
+	max_life = resolvers.rngavg(120,140),
+	combat_armor = 12, combat_def = 4,
+}
+
+newEntity{ base = "BASE_NPC_TROLL",
+	name = "mountain troll thunderer", color=colors.AQUAMARINE, image="npc/troll_mt.png",
+	desc = [[A large and athletic troll with an extremely tough and warty hide.]],
+	rarity = 5,
+	rank = 3,
+	max_life = resolvers.rngavg(120,140),
+	combat_armor = 8, combat_def = 4,
+	resolvers.talents{
+		[Talents.T_LIGHTNING]=4,
+	},
+}
diff --git a/game/modules/boot/data/gfx/npc/armored_skeleton_warrior.png b/game/modules/boot/data/gfx/npc/armored_skeleton_warrior.png
new file mode 100644
index 0000000000000000000000000000000000000000..00cbcabaab62a815eb6b327de79fdc53fcf8b513
GIT binary patch
literal 1582
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

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/canine_dw.png b/game/modules/boot/data/gfx/npc/canine_dw.png
new file mode 100644
index 0000000000000000000000000000000000000000..d84ce1a8175fbe4fd67afc5c0721e80c10cf6634
GIT binary patch
literal 3466
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

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/canine_fox.png b/game/modules/boot/data/gfx/npc/canine_fox.png
new file mode 100644
index 0000000000000000000000000000000000000000..8953918dd4248bfc69673af6f016ec6446935ff9
GIT binary patch
literal 3178
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

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/canine_gw.png b/game/modules/boot/data/gfx/npc/canine_gw.png
new file mode 100644
index 0000000000000000000000000000000000000000..a69f00dec334894976b0994de802e5ca8a7861c1
GIT binary patch
literal 3640
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

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/canine_w.png b/game/modules/boot/data/gfx/npc/canine_w.png
new file mode 100644
index 0000000000000000000000000000000000000000..a8eaac992e3e5ffbcb2a92b0c46bf011c4473522
GIT binary patch
literal 3319
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

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/canine_warg.png b/game/modules/boot/data/gfx/npc/canine_warg.png
new file mode 100644
index 0000000000000000000000000000000000000000..2316dbf3f1b62737e2916ba530d85684a0970cab
GIT binary patch
literal 3694
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
USY*!D{|zAzH}4%K+qjAU2YOIldjJ3c

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/canine_ww.png b/game/modules/boot/data/gfx/npc/canine_ww.png
new file mode 100644
index 0000000000000000000000000000000000000000..8a026700505f16fd7a568fd8554903226b07c852
GIT binary patch
literal 3847
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
Xh2JWgmUSEc1<=lq_iVox$~pEw#}}s&

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/degenerated_skeleton_warrior.png b/game/modules/boot/data/gfx/npc/degenerated_skeleton_warrior.png
new file mode 100644
index 0000000000000000000000000000000000000000..f8f88c0bb8a14b30931954be40af9e286d12b3d0
GIT binary patch
literal 994
zcmV<810DQ{P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#24YJ`L;ynoLjXg28M;*f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igh&
z6Dcu<g=p0P000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0009$Nkl<Z
zSi`-RTWDNW6o$Wb&csA(%?vHA6l7A3V5}}P#yr$ir5zM1R;`Ly@sd7>r7iXHU|#B*
zRD2XmFCvIOM1uHY5vfh1RfHC$=n6Kdq0?f`LoS_+lR}x>_GL$gVUQ*{CqEoG>;q^0
z`(OY5*A^B5=iFn!9l)%Je8dtUizILnxD13MqDvtVETZ_Gz$M^A;DU25wX6h0<Q(uT
zFak^hv&%}r;{xzLP!<u#a>C5k)%jq_kZUN2s$yn`oO8E|$lt(IEiEl)M5L!wDkXvM
zfX%>ORXq|(3(Rc(^+7ZHty-<#*xA`RQLEK@fcMJf^4U_UbkI3B5QgCw&bblb$0$AU
zqM12h5ZKq<-TlVg++4eetOou8wgEGhN~M@ir(dqsY9qiSb;Pd;iU0ZbgsRHC8qT?{
zN~N+vL=4ygtOZ^Q!|+nESS&i{z6Ksp)uk)o`~J-QZd8>Z2*#$Tr^kT;a1po(C<H+;
zIW;wPOCpg7fYC@=Fu#k&-H6B}a03tmGe8&6=2LMckd8YC?(=PX4QK_P1n%{PbDmIS
z9%zQQft&sF4e$rB7cgKIP>EZCFIDv@um<P@_NeOjsyYii1dPS4z};qc3>fwyHeqIG
zfwzG5en`ctz&pV8Knrjc*a+MMJnmaE5t{=3NWK8P2~>f<fOWuUz+oU0s|Wm%T<c9Y
z3QVZ#PGEy`Zg<;?6$R(qrno2Jbv~Z!*S@Mbcl)kv_Ltws#}AoV??U2O7D!+XFr=!R
z>(<__RjavHIDh*1@e}<611m*jE-n+^5B$)ub}k6RbXO)btl8|oEy?63*;HzMHkFE&
zfS2{QCIkw=n3>Vj+xx+{g~HRo0pQs<Ot>F-zTwkGKM(%H$$WkXaCu96`=<|Y-P)hY
zWL}L*frG&Q29tdbWSWfO;Y2cdxHvQOaYskT5$9Ya3Y-F7Zz%RBFy83=lleTW`}%$^
zUb%8Cm&*-_NF-5wmrucZ^a4LMyNC=94wijNMs^C$1C3g~0<<mkDz;bxo0`o0QQ(A+
z>DUQu2aYy);{fm+u-(iajb#{ldHaFRCOLqr4w+frPsG^fz&0~$jrza;0tWa)RzfKf
QN&o-=07*qoM6N<$f^(m|wg3PC

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/skeleton_mage.png b/game/modules/boot/data/gfx/npc/skeleton_mage.png
new file mode 100644
index 0000000000000000000000000000000000000000..f2f45e2ad85bcbfbfb300c737aabdadc2cc22657
GIT binary patch
literal 1388
zcmV-y1(W)TP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igh&
z6E`G38MEO4000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000EXNkl<Z
zSi`-SeQ1?s7{-71-kqKKwT+$OHfLzgoSXX2O+yx9K~W@GDn%cZ7$q8s+K1Mbr7jgR
zGSYz<{t=O>MNlT<tUytyku!X3)%s9|dNk|k@;KYh&N+8~^c*<8p0iGFc>nXjxu5e~
z*L&U9eZS8uTt}$teZY92Q$)5gkfEwMedQbdO=Z13u@kC#L{-1*FP@|zAR?ma{;+l0
z&eg?k(b916a!bz8oZ60qXPQ==ThKUAPoL4glLt=kIK1J=9l@i&?_8I+Wi&TBRCR@_
z?o-t*Hyqp;Gs2SS7>M&E(~WIyZSO>*(Fzec1I+dLd@Uj}B@&4gsOmSPMvYomP*AWh
zle0>PjI2J}b@~`URwlks)%hhQC0XU=<-vG7J_UHAx3~9bBob*-)t5x%!~FdG8MZz9
zjAemU58M>HIls~0L`DQe1XZmrEG*pI)zy_RB1OO@U=|RHMx)^|W5&!Akp^I@sy?Ht
zzLelJ`eM=EdnQC{M!%l3%*lv=B{5W0tD@291Q9X7qd+k*&vBf4!{Kn)?pqBQ;C)qX
zP*q=YXN@nbEGg2`oLlm$YI?)bSjHYu)pvp2#+XGS5(Z+xgTNu+H{f>Hbt@Akv#Pyq
zb6Z3twvZJ#Sz6}L9dt6*9lyY^*tG13uOll%4|a;k9uYYY3<ew^1XKdKz&TIJ5RvDA
z&w%$-_5Q7F;Bx%R?34cEzQew~MHiyyc5VE-kxU6pwChwL8(0eXf!RPUaNg@18>d9%
z31C<}9^bU;#FDzQ%Hh!}XOh#I6?`+L2eg54DF|G$>#M+Spaj?t{0uAx78_$y8rZJe
zMWp40rxwmF9bdAk-T!s*o^bOgsq0-&qo)NYs_Kh&2#H<qGRAZmW9l;<@vSW_6>F9+
zKkdzBd%(-crAjwZBun_y*7E}qnQXUAGRAxkd}$3FG{zhS>Rs1u?yHr@78JY!obu+f
zlB5S^GT9VzmX|H_nZV|xR$2=T0(?L>PzO{4cmJ0Pj^orhj?<P_0a*{)z);3fNEbc!
z=XD}dV`T?;9C+Tg;VEDQumec@QmP090Lp+u;OUA$fc8)*jRM0tM(MB;x|w17cv0f%
zUDw49pT)p&An3a8lfVSv;Utn*g#~*H*xMcoT?Kxv0<CMRxwxvB>G$T*b7i~a4r%e6
z*8v1v*Znl<w;-_37=!D&7-M`uuO*y_v4FoK5OCT<p;%fIQu|tvpGx=BJ!mlg!Mjr^
zS^ymIzM+9BuIsj11tbA(<<GXm>#!I68UiA6NL4qY8U+4GLEtt!ev{(|dqGW<DUvLI
zMIf-&D!0g6|7#Wamqc@#iwHn@3IcxtKlaf8tw3peC=^eX%ybkdo^B=Zm?u>S<fby9
zjVhosT{2?=7N7}O=>hu~sPUN2>zn3&6R-dWfn^@BUw~iJDWIw&fIIt5AnC2>z3toz
ze49#via;P&L`DPkwj=sY-~{0Pcvz6m1MQ(uH_!#-dEI}#1g6_dNOBwpzOZB3tH49R
zNFY2=C71(j^>|}F@CY!+7&9{oycYNfc(y$h>PdHC_W$UB`F5lpN@37l#+Zxtl9HH!
u-vir#uLkOiXqGX?pXvUD>C%}m5&r;YBmS1#i|f$<0000<MNUMnLSTZMse(iR

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/skeleton_warrior.png b/game/modules/boot/data/gfx/npc/skeleton_warrior.png
new file mode 100644
index 0000000000000000000000000000000000000000..9bc98593afb983bfc3c0b7c9538e8d96b7dac0e0
GIT binary patch
literal 1153
zcmV-{1b+L8P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igh&
z6E7&Vv}cn5000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000BrNkl<Z
zSi`lKZ%CbG7{-6k>yH15O>sL(pdvenO?{!A2^xCPNHm))MX^6iW+S7_So;td`;t<y
zZwk{WLS*=5WS|K-E9#6xvr$w&(iF0Rm3UG|XNvQ9PUqZxc^!5*vCX~b{&>F+&wV}D
zeLdH6zlu1~+S+<%dwctjv9YmF<9!#A<3J%0P)dEw1B4MTxwW;GxxBnQ+Sk{2psTAZ
z-jV^}Mc_>m6>hgX+S1Z87U%RwMC4l$c}+w<6Ol~Y82~U0<MpMbr4#M#?L{3O9e46d
zsq4TD@HMak1QNzVO-)U}<MI3)hlRIA<g$o-kg(!yZEZ9(G&JSr=1N^%-7`CRt@Wc8
zh($Z<sJksFEiL^m6bfZdO--F&Sy_1!_!DSyI2_lMQtn_d_>j}-3@t7$7M7Qn`)$(z
zKy!05+1c4IM<S8Tp`oFd3JMCAqS2@uI3Es&e+-2}7l3zCQ&UIF%F0q~6(PXr=qM8t
z6IasG(yk2;4;O{Q;r&XfgTOk_0Njj3BAdy{$ww`3uonQpz`y{#y}kV+LQhXmlVKRM
z!1KT(KwDB$($nkf>nlpBWf7?m5qkl2c6L%*Tbq-gpZ~ef=Tn=To2!-p_XD>K!&q5c
zTgwB!0xFbJ_5u)*6cM@Ya=A_ggF!|{Mvgli4h7r<9s^PVzfx))$P$r!TLAzyN~w*(
z!NJwq+S-WM>&+Y=AHS56l43-o(Px39mLUOr1RS%?3q%AFIV>ViiO5Nx&(~N~R3sjc
z=da4jO23F4&{})6)`zV1Cq(2xLX1g7vR7AE&lVOI{$Aj8-k836b$(`Mrh8YLszoIG
zenq(No*hdme}8}fPm`0A8%y)^58qx}%Sua6Uz(en`ymhre3OxpF`|_6+kOpqM|E}e
zTN@i2hjNOG_0+|S2XpfBPN%1*yZwGYN~xKISn;km0PE_VjYgy4P$2N??DX{ZvHJS&
zlv3}Srn!(1BiaemG_lO*4Z|>gNq0KmJKf#wHj<K#0Ij<~CPo8RECN}kY2F!BBpUSt
zm$lZIris?t0fa5U_G$pg0KBo?0o+z`0Clg$_rkyvfG;L@-5OAL+7wEN2CUN^jsxHp
zFlYNr_&*{%2fPsTsT@e%ivah+zy;u3OtDXZ$M2`_55m9|;7m-hUx9^q3{+KB?Q^+Y
z%FbI*3^-!PM&SE+40yfXe-;)Nq@<+8HUKw(*w^NjyJ=u{cGflk71j{)pZ$R^fs+Z<
zfEA6vhcViCA9xOE)LPdk#ELC?PXVqtK7eVOm$cS@179TUPf2UtptVl1d*6QnApoa9
T4=V7q00000NkvXXu0mjf@lXOg

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/troll_c.png b/game/modules/boot/data/gfx/npc/troll_c.png
new file mode 100644
index 0000000000000000000000000000000000000000..3b90530ca3d1f5eacf0e5f9c25f70ac90bcbfd8a
GIT binary patch
literal 2725
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
H@Us37k&*F>

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/troll_f.png b/game/modules/boot/data/gfx/npc/troll_f.png
new file mode 100644
index 0000000000000000000000000000000000000000..010069759326f8e031559e9e3c7cb3e4315f363f
GIT binary patch
literal 2213
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

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/troll_m.png b/game/modules/boot/data/gfx/npc/troll_m.png
new file mode 100644
index 0000000000000000000000000000000000000000..9b04cfe50d7a64b5b7199c3073b54127ae20c789
GIT binary patch
literal 2331
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

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/troll_mt.png b/game/modules/boot/data/gfx/npc/troll_mt.png
new file mode 100644
index 0000000000000000000000000000000000000000..6632624cc142f60ca0ec60f4187377e7858ca3c2
GIT binary patch
literal 2938
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
aAplkrlVbWWA5q=Oz}`Lk9Ut$868{I36JW9c

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/npc/troll_s.png b/game/modules/boot/data/gfx/npc/troll_s.png
new file mode 100644
index 0000000000000000000000000000000000000000..dfcefa0afcb494e1f9a331c36048868de24c75fb
GIT binary patch
literal 2419
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
Q1qt}%<EW6jUD&CA0JpDFZvX%Q

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/particles/acid.lua b/game/modules/boot/data/gfx/particles/acid.lua
new file mode 100644
index 0000000000..6a5cfb89e9
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/acid.lua
@@ -0,0 +1,38 @@
+-- ToME - Tales of Middle-Earth
+-- 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 {
+	base = 1000,
+
+	angle = { 0, 360 }, anglev = { 2000, 4000 }, anglea = { 200, 600 },
+
+	life = { 5, 10 },
+	size = { 3, 6 }, sizev = {0, 0}, sizea = {0, 0},
+
+	r = {0, 0}, rv = {0, 0}, ra = {0, 0},
+	g = {80, 200}, gv = {0, 10}, ga = {0, 0},
+	b = {0, 0}, bv = {0, 0}, ba = {0, 0},
+	a = {255, 255}, av = {0, 0}, aa = {0, 0},
+
+}, function(self)
+	self.nb = (self.nb or 0) + 1
+	if self.nb < 4 then
+		self.ps:emit(100)
+	end
+end
diff --git a/game/modules/boot/data/gfx/particles/bolt_fire.lua b/game/modules/boot/data/gfx/particles/bolt_fire.lua
new file mode 100644
index 0000000000..06a5245b98
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/bolt_fire.lua
@@ -0,0 +1,51 @@
+-- ToME - Tales of Middle-Earth
+-- 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 = rng.range(200, 255)/255,   rv = 0, ra = 0,
+		g = rng.range(120, 170)/255,   gv = 0.005, ga = 0.0005,
+		b = rng.range(0, 10)/255,      bv = 0, ba = 0,
+		a = rng.range(25, 220)/255,    av = static and -0.034 or 0, aa = 0.005,
+	}
+end, },
+function(self)
+	self.ps:emit(30)
+end,
+30*6
diff --git a/game/modules/boot/data/gfx/particles/fireflash.lua b/game/modules/boot/data/gfx/particles/fireflash.lua
new file mode 100644
index 0000000000..f26ba9ee4b
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/fireflash.lua
@@ -0,0 +1,96 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+--[[
+-- Make up the grids list
+local gs = {}
+
+-- Compute the clipping circle
+local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+for i = -radius, radius do for j = -radius, radius  do
+	local lastx, lasty = 0, 0
+	local l = line.new(0, 0, i, j)
+	local lx, ly = l()
+	while lx do
+		if grids[lx+tx] and grids[lx+tx][ly+ty] then
+			lastx, lasty = lx, ly
+		else
+			gs[lx] = gs[lx] or {}
+			gs[lx][ly] = {x=lastx, y=lasty, radius=math.sqrt(lastx^2 + lasty^2)}
+--			print("block", lx, ly, "=>", math.sqrt(lastx^2 + lasty^2))
+		end
+		lx, ly = l()
+	end
+end end
+]]
+
+local nb = 0
+return { generator = function()
+	local radius = radius
+	local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+	local ad = rng.float(0, 360)
+	local a = math.rad(ad)
+	local r = rng.float(sradius - 5, sradius)
+	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)
+--[[
+	if gs[bx] and gs[bx][by] and rng.chance(2) then
+--		print("block at angle", ad, radius, ":=>", gs[bx][by].radius)
+		radius = gs[bx][by].radius
+		sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+		local r = rng.float(sradius - 5, sradius)
+		x = r * math.cos(a)
+		y = r * math.sin(a)
+	end
+--]]
+	local static = rng.percent(40)
+
+	return {
+		trail = 1,
+		life = 24,
+		size = 3, sizev = static and 0.05 or 0.15, sizea = 0,
+
+		x = x, xv = 0, xa = 0,
+		y = y, yv = 0, ya = 0,
+		dir = static and a + math.rad(90 - rng.range(10, 20)) or a, dirv = 0, dira = 0,
+		vel = static and -2 or 0.5 * (-1-nb) * radius / 2.7, velv = 0, vela = static and -0.01 or rng.float(-0.3, -0.2) * 0.3,
+
+		r = rng.range(200, 255)/255,   rv = 0, ra = 0,
+		g = rng.range(120, 170)/255,   gv = 0.005, ga = 0.0005,
+		b = rng.range(0, 10)/255,      bv = 0, ba = 0,
+		a = rng.range(25, 220)/255,    av = static and -0.034 or 0, aa = 0.005,
+	}
+end, },
+function(self)
+	if nb < 5 then
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+	end
+end,
+5*radius*266
diff --git a/game/modules/boot/data/gfx/particles/firetrail.lua b/game/modules/boot/data/gfx/particles/firetrail.lua
new file mode 100644
index 0000000000..627a958d8e
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/firetrail.lua
@@ -0,0 +1,56 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+local nb = 0
+
+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.1, sradius / 2)
+	local x = r * math.cos(a)
+	local y = r * math.sin(a)
+	local bx = math.floor(x / engine.Map.tile_w)
+	local by = math.floor(y / engine.Map.tile_h)
+	local static = rng.percent(40)
+
+	return {
+		trail = 1,
+		life = 3 + 9 * (sradius - r) / sradius,
+		size = 3, sizev = 0, sizea = 0,
+
+		x = x, xv = 0, xa = 0,
+		y = y, yv = 0, ya = 0,
+		dir = 0, dirv = 0, dira = 0,
+		vel = 0, velv = 0, vela = 0,
+
+		r = rng.range(200, 255)/255,   rv = 0, ra = 0,
+		g = rng.range(120, 170)/255,   gv = 0.005, ga = 0.0005,
+		b = rng.range(0, 10)/255,      bv = 0, ba = 0,
+		a = rng.range(25, 220)/255,    av = static and -0.034 or 0, aa = 0.005,
+	}
+end, },
+function(self)
+	if nb < 1 then
+		self.ps:emit(40)
+	end
+	nb = nb + 1
+end,
+40
diff --git a/game/modules/boot/data/gfx/particles/flame.lua b/game/modules/boot/data/gfx/particles/flame.lua
new file mode 100644
index 0000000000..4fb697c6de
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/flame.lua
@@ -0,0 +1,38 @@
+-- ToME - Tales of Middle-Earth
+-- 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 {
+	base = 1000,
+
+	angle = { 0, 360 }, anglev = { 2000, 4000 }, anglea = { 200, 600 },
+
+	life = { 5, 10 },
+	size = { 3, 6 }, sizev = {0, 0}, sizea = {0, 0},
+
+	r = {200, 255}, rv = {0, 0}, ra = {0, 0},
+	g = {120, 170}, gv = {0, 0}, ga = {0, 0},
+	b = {0, 0}, bv = {0, 0}, ba = {0, 0},
+	a = {255, 255}, av = {0, 0}, aa = {0, 0},
+
+}, function(self)
+	self.nb = (self.nb or 0) + 1
+	if self.nb < 4 then
+		self.ps:emit(100)
+	end
+end
diff --git a/game/modules/boot/data/gfx/particles/golden_shield.lua b/game/modules/boot/data/gfx/particles/golden_shield.lua
new file mode 100644
index 0000000000..90126fa96b
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/golden_shield.lua
@@ -0,0 +1,46 @@
+-- ToME - Tales of Middle-Earth
+-- 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 ad = rng.range(0, 360)
+	local a = math.rad(ad)
+	local dir = math.rad(ad + 90)
+	local r = rng.range(12, 20)
+	local dirv = math.rad(1)
+
+	return {
+		trail = 1,
+		life = 10,
+		size = 4, sizev = -0.1, sizea = 0,
+
+		x = r * math.cos(a), xv = 0, xa = 0,
+		y = r * math.sin(a), yv = 0, ya = 0,
+		dir = dir, dirv = dirv, dira = 0,
+		vel = rng.percent(50) and -1 or 1, velv = 0, vela = 0,
+
+		r = rng.range(220, 255)/255,  rv = 0, ra = 0,
+		g = rng.range(200, 230)/255,  gv = 0, ga = 0,
+		b = 0,                        bv = 0, ba = 0,
+		a = rng.range(25, 220)/255,   av = 0, aa = 0,
+	}
+end, },
+function(self)
+	self.ps:emit(10)
+end,
+100
diff --git a/game/modules/boot/data/gfx/particles/lightning.lua b/game/modules/boot/data/gfx/particles/lightning.lua
new file mode 100644
index 0000000000..33e8acccd9
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/lightning.lua
@@ -0,0 +1,83 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+-- Make the 2 main forks
+local forks = {{}, {}}
+local m1 = forks[1]
+local m2 = forks[2]
+local tiles = math.ceil(math.sqrt(tx*tx+ty*ty))
+local tx = tx * engine.Map.tile_w
+local ty = ty * engine.Map.tile_h
+local breakdir = math.rad(rng.range(-8, 8))
+m1.bx = 0
+m1.by = 0
+m1.thick = 5
+m1.dir = math.atan2(ty, tx) + breakdir
+m1.size = math.sqrt(tx*tx+ty*ty) / 2
+
+m2.bx = m1.size * math.cos(m1.dir)
+m2.by = m1.size * math.sin(m1.dir)
+m2.thick = 5
+m2.dir = math.atan2(ty, tx) - breakdir
+m2.size = math.sqrt(tx*tx+ty*ty) / 2
+
+-- Add more forks
+for i = 1, math.min(math.max(3, m1.size / 5), 20) do
+	local m = rng.percent(50) and forks[1] or forks[2]
+	if rng.percent(60) then m = rng.table(forks) end
+	local f = {}
+	f.thick = 2
+	f.dir = m.dir + math.rad(rng.range(-30,30))
+	f.size = rng.range(6, 25)
+	local br = rng.range(1, m.size)
+	f.bx = br * math.cos(m.dir) + m.bx
+	f.by = br * math.sin(m.dir) + m.by
+	forks[#forks+1] = f
+end
+
+-- Populate the lightning based on the forks
+return { generator = function()
+	local f = rng.table(forks)
+	local a = f.dir
+	local rad = rng.range(-3,3)
+	local ra = math.rad(rad)
+	local r = rng.range(1, f.size)
+
+	return {
+		life = life or 4,
+		size = f.thick, sizev = 0, sizea = 0,
+
+		x = r * math.cos(a) + 3 * math.cos(ra) + f.bx, xv = 0, xa = 0,
+		y = r * math.sin(a) + 3 * math.sin(ra) + f.by, yv = 0, ya = 0,
+		dir = 0, dirv = 0, dira = 0,
+		vel = 0, velv = 0, vela = 0,
+
+		r = rng.range(140, 200)/255, rv = 0, ra = 0,
+		g = rng.range(180, 220)/255, gv = 0, ga = 0,
+		b = rng.range(220, 240)/255, bv = 0, ba = 0,
+		a = rng.range(230, 255)/255, av = 0, aa = 0,
+	}
+end, },
+function(self)
+	self.nb = (self.nb or 0) + 1
+	if self.nb < 4 then
+		self.ps:emit(230*tiles)
+	end
+end,
+4*(nb_particles or 230)*tiles
diff --git a/game/modules/boot/data/gfx/particles/mana_beam.lua b/game/modules/boot/data/gfx/particles/mana_beam.lua
new file mode 100644
index 0000000000..38992e1699
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/mana_beam.lua
@@ -0,0 +1,58 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+-- Make the ray
+local ray = {}
+local tiles = math.ceil(math.sqrt(tx*tx+ty*ty))
+local tx = tx * engine.Map.tile_w
+local ty = ty * engine.Map.tile_h
+local breakdir = math.rad(rng.range(-8, 8))
+ray.dir = math.atan2(ty, tx)
+ray.size = math.sqrt(tx*tx+ty*ty)
+
+-- Populate the beam based on the forks
+return { generator = function()
+	local a = ray.dir
+	local rad = rng.range(-3,3)
+	local ra = math.rad(rad)
+	local r = rng.range(1, ray.size)
+
+	return {
+		life = 14,
+		size = rng.range(4, 6), sizev = -0.1, sizea = 0,
+
+		x = r * math.cos(a) + 2 * math.cos(ra), xv = 0, xa = 0,
+		y = r * math.sin(a) + 2 * math.sin(ra), yv = 0, ya = 0,
+		dir = rng.percent(50) and ray.dir + math.rad(rng.range(50, 130)) or ray.dir - math.rad(rng.range(50, 130)), dirv = 0, dira = 0,
+		vel = rng.percent(30) and 1 or 0, velv = -0.1, vela = 0.01,
+
+		r = rng.range(180, 220)/255,  rv = 0, ra = 0,
+		g = rng.range(0, 0)/255,      gv = 0, ga = 0,
+		b = rng.range(200, 255)/255,      bv = 0, ba = 0,
+		a = rng.range(80, 220)/255,   av = 0, aa = 0,
+	}
+end, },
+function(self)
+	self.nb = (self.nb or 0) + 1
+	if self.nb < 6 then
+		self.ps:emit(30*tiles)
+	end
+end,
+14*30*tiles,
+"particle_torus"
diff --git a/game/modules/boot/data/gfx/particles/sunburst.lua b/game/modules/boot/data/gfx/particles/sunburst.lua
new file mode 100644
index 0000000000..081f87e2e9
--- /dev/null
+++ b/game/modules/boot/data/gfx/particles/sunburst.lua
@@ -0,0 +1,132 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+-- Make up the grids list
+local gs = {}
+max_alpha = max_alpha or 220
+
+-- Compute the clipping circle
+local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+for i = -radius, radius do for j = -radius, radius  do
+	local lastx, lasty = 0, 0
+	local l = line.new(0, 0, i, j)
+	local lx, ly = l()
+	while lx do
+		if grids[lx+tx] and grids[lx+tx][ly+ty] then
+			lastx, lasty = lx, ly
+		else
+			gs[lx] = gs[lx] or {}
+			gs[lx][ly] = {x=lastx, y=lasty, radius=math.sqrt(lastx^2 + lasty^2)}
+--			print("block", lx, ly, "=>", math.sqrt(lastx^2 + lasty^2))
+		end
+		lx, ly = l()
+	end
+end end
+
+local nb = 0
+return { generator = function()
+	local radius = radius
+	local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+	local ad = rng.float(0, 360)
+	local a = math.rad(ad)
+	local r = rng.float(sradius - 12, sradius)
+	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)
+	if gs[bx] and gs[bx][by] and rng.chance(2) then
+--		print("block at angle", ad, radius, ":=>", gs[bx][by].radius)
+		radius = gs[bx][by].radius
+		sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
+		local r = rng.float(sradius - 5, sradius)
+		x = r * math.cos(a)
+		y = r * math.sin(a)
+	end
+	local static = rng.percent(40)
+
+	return {
+		trail = 1,
+		life = 24,
+		size = 3, sizev = static and 0.05 or 0.15, sizea = 0,
+
+		x = x, xv = 0, xa = 0,
+		y = y, yv = 0, ya = 0,
+		dir = static and a + math.rad(90 + rng.range(10, 20)) or a, dirv = 0, dira = 0,
+		vel = static and 2 or 0.5 * (-1-nb) * radius / 2.7, velv = 0, vela = static and 0.01 or rng.float(-0.3, -0.2) * 0.3,
+
+		r = rng.range(220, 255)/255,  rv = 0, ra = 0,
+		g = rng.range(200, 230)/255,  gv = 0, ga = 0,
+		b = 0,                        bv = 0, ba = 0,
+		a = rng.range(25, max_alpha)/255,    av = static and -0.034 or 0, aa = 0.005,
+	}
+end, },
+function(self)
+	if nb < 5 then
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+		self.ps:emit(radius*266)
+		nb = nb + 1
+	end
+end,
+5*radius*266
+
+--[[
+local nb = 0
+return { generator = function()
+	local ad = rng.range(0, 360)
+	local a = math.rad(ad)
+	local r = rng.range(2, sradius)
+	local boundx = r * math.cos(a)
+	local boundy = r * math.sin(a)
+	local x = math.floor(boundx / engine.Map.tile_w) + tx
+	local y = math.floor(boundy / engine.Map.tile_h) + ty
+	if not grids[x] or not grids[x][y] then return end
+
+	return {
+		trail = 1,
+		life = 12,
+		size = 3, sizev = 0.3, sizea = 0,
+
+		x = boundx, xv = 0, xa = 0,
+		y = boundy, yv = 0, ya = 0,
+--		x = r * math.cos(a), xv = -0.1, xa = 0,
+--		y = r * math.sin(a), yv = -0.1, ya = 0,
+		dir = a + 5 * math.rad(rng.range(10, 20)), dirv = math.rad(rng.range(10, 20)), dira = -math.rad(2),
+		vel = 1, velv = 0, vela = 0.1,
+
+		r = rng.range(200, 255)/255,   rv = 0, ra = 0,
+		g = rng.range(120, 170)/255,   gv = 0, ga = 0,
+		b = rng.range(0, 10)/255,      bv = 0, ba = 0,
+		a = rng.range(25, 220)/255,    av = 0, aa = 0,
+	}
+end, },
+function(self)
+	if nb < 2 then
+		self.ps:emit(800)
+		nb = nb + 1
+	end
+end,
+5000
+]]
\ No newline at end of file
diff --git a/game/modules/boot/data/gfx/shaders/main_fbo.frag b/game/modules/boot/data/gfx/shaders/main_fbo.frag
new file mode 100644
index 0000000000..d092ce9fc3
--- /dev/null
+++ b/game/modules/boot/data/gfx/shaders/main_fbo.frag
@@ -0,0 +1,172 @@
+uniform float hp_warning;
+uniform float motionblur;
+uniform float blur;
+uniform float tick;
+uniform sampler2D noisevol;
+uniform vec2 texSize;
+uniform sampler2D tex;
+uniform vec3 colorize;
+
+void main(void)
+{
+	gl_FragColor = texture2D(tex, gl_TexCoord[0].xy);
+
+	if (motionblur > 0.0)
+	{
+		int blursize = int(motionblur);
+		vec2 offset = 0.8/texSize;
+
+		float fTime0_X = tick / 20000.0;
+		float coord = gl_TexCoord[0].x + gl_TexCoord[0].y * texSize[0];
+		float noisy1 = texture2D(noisevol,vec2(coord,fTime0_X)).r;
+		float noisy2 = texture2D(noisevol,vec2(coord/5.0,fTime0_X/1.5)).r;
+		float noisy3 = texture2D(noisevol,vec2(coord/7.0,fTime0_X/2)).r;
+		float noisy = (noisy1+noisy2+noisy3)/3.0;
+
+		// Center Pixel
+		vec4 sample = vec4(0.0,0.0,0.0,0.0);
+		float factor = ((float(blursize)*2.0)+1.0);
+		factor = factor*factor;
+
+		if (noisy < 0.25)
+		{
+			for(int i = -blursize; i <= 0; i++)
+			{
+				for(int j = -blursize; j <= 0; j++)
+				{
+					sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
+				}
+			}
+		}
+		else if (noisy < 0.50)
+		{
+			for(int i = 0; i <= blursize; i++)
+			{
+				for(int j = 0; j <= blursize; j++)
+				{
+					sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
+				}
+			}
+		}
+		else if (noisy < 0.75)
+		{
+			for(int i = 0; i <= blursize; i++)
+			{
+				for(int j = -blursize; j <= 0; j++)
+				{
+					sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
+				}
+			}
+		}
+		else
+		{
+			for(int i = -blursize; i <= 0; i++)
+			{
+				for(int j = 0; j <= blursize; j++)
+				{
+					sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
+				}
+			}
+		}
+		sample /= float((blursize*1.5) * (blursize*0.5));
+//		gl_FragColor = sample * (0.3 + noise * 0.7);
+		gl_FragColor = sample;
+	}
+	else if (blur > 0.0)
+	{
+		int blursize = int(blur);
+		vec2 offset = 1.0/texSize;
+
+		// Center Pixel
+		vec4 sample = vec4(0.0,0.0,0.0,0.0);
+		float factor = ((float(blursize)*2.0)+1.0);
+		factor = factor*factor;
+
+		for(int i = -blursize; i <= blursize; i++)
+		{
+			for(int j = -blursize; j <= blursize; j++)
+			{
+				sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
+			}
+		}
+		sample /= float((blur*2.0) * (blur*2.0));
+		gl_FragColor = sample;
+	}
+
+	if (colorize.r > 0.0 || colorize.g > 0.0 || colorize.b > 0.0)
+	{
+		float grey = gl_FragColor.r*0.3+gl_FragColor.g*0.59+gl_FragColor.b*0.11;
+		gl_FragColor = vec4(vec3(colorize*grey),1.0);
+	}
+
+	if (hp_warning > 0.0)
+	{
+		vec4 hp_warning_color = vec4(hp_warning / 1.9, 0.0, 0.0, hp_warning / 1.5);
+		float dist = length(gl_TexCoord[0].xy - vec2(0.5)) / 2.0;
+		gl_FragColor = mix(gl_FragColor, hp_warning_color, dist);
+	}
+}
+
+/*uniform sampler2D tex;
+uniform vec2 texSize;
+int blursize = 5;
+
+void main(void)
+{
+	vec2 offset = 1.0/texSize;
+
+	// Center Pixel
+	vec4 sample = vec4(0.0,0.0,0.0,0.0);
+	float factor = ((float(blursize)*2.0)+1.0);
+	factor = factor*factor;
+
+	for(int i = -blursize; i <= blursize; i++)
+	{
+		for(int j = -blursize; j <= blursize; j++)
+		{
+			sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
+		}
+	}
+	sample /= float((blursize*2) * (blursize*2));
+
+	float grey = sample.r*0.3+sample.g*0.59+sample.b*0.11;
+	vec3 color = vec3(1, 0, 0);
+	gl_FragColor = vec4(vec3(color*grey),1.0);
+}
+*/
+/*
+uniform sampler2D tex;
+uniform sampler3D noiseVol;
+uniform float tick;
+float do_blur = 3.0;
+uniform vec2 texSize;
+
+void main(void)
+{
+	if (do_blur > 0.0)
+	{
+		vec2 offset = 1.0/texSize;
+		offset.y += texture3D(noiseVol, vec3(gl_TexCoord[0].xy, tick/100000))/30;
+
+		// Center Pixel
+		vec4 sample = vec4(0.0,0.0,0.0,0.0);
+		float factor = ((float(do_blur)*2.0)+1.0);
+		factor = factor*factor;
+
+		for(int i = -do_blur; i <= do_blur; i++)
+		{
+			for(int j = -do_blur; j <= do_blur; j++)
+			{
+				sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
+			}
+		}
+		sample /= float((do_blur*2) * (do_blur*2));
+
+		gl_FragColor = sample;
+	}
+
+	float grey = gl_FragColor.r*0.3+gl_FragColor.g*0.59+gl_FragColor.b*0.11;
+	vec3 color = vec3(1, 0, 0);
+	gl_FragColor = vec4(vec3(color*grey),1.0);
+}
+*/
diff --git a/game/modules/boot/data/gfx/shaders/main_fbo.lua b/game/modules/boot/data/gfx/shaders/main_fbo.lua
new file mode 100644
index 0000000000..95fb5732e3
--- /dev/null
+++ b/game/modules/boot/data/gfx/shaders/main_fbo.lua
@@ -0,0 +1,28 @@
+-- ToME - Tales of Middle-Earth
+-- 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 {
+	frag = "main_fbo",
+	vert = nil,
+	args = {
+		tex = { texture = 0 },
+		noisevol = { texture = 1 },
+	},
+	clone = false,
+}
diff --git a/game/modules/boot/data/gfx/shaders/water.frag b/game/modules/boot/data/gfx/shaders/water.frag
new file mode 100644
index 0000000000..264bbed35b
--- /dev/null
+++ b/game/modules/boot/data/gfx/shaders/water.frag
@@ -0,0 +1,21 @@
+uniform float tick;
+uniform sampler3D noisevol;
+uniform vec2 mapCoord;
+uniform vec4 displayColor;
+uniform vec4 color1;
+uniform vec4 color2;
+
+void main(void)
+{
+	float fTime0_X = tick / 100000.0;
+	vec2 coord = mapCoord+gl_TexCoord[0].xy;
+	float noisy = texture3D(noisevol,vec3(coord,fTime0_X)).r;
+	float noisy2 = texture3D(noisevol,vec3(coord/5.0,fTime0_X)).r;
+	float noisy3 = texture3D(noisevol,vec3(coord/7.0,fTime0_X)).r;
+	float noise = (noisy+noisy2+noisy3)/3.0;
+
+	float bump = 1.0-abs((2.0 * noise)-1.0);
+	bump *= bump - 0.3;
+	gl_FragColor = mix(color1, color2, bump) * displayColor;
+	gl_FragColor.a = 0.4;
+}
diff --git a/game/modules/boot/data/gfx/shaders/water.lua b/game/modules/boot/data/gfx/shaders/water.lua
new file mode 100644
index 0000000000..7e2c2cea2d
--- /dev/null
+++ b/game/modules/boot/data/gfx/shaders/water.lua
@@ -0,0 +1,29 @@
+-- ToME - Tales of Middle-Earth
+-- 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 {
+	frag = "water",
+	vert = nil,
+	args = {
+		noisevol = { texture = 1 },
+		color1 = {0,0,1,1},
+		color2 = {0,0.6,0.8,1},
+	},
+	clone = false,
+}
diff --git a/game/modules/boot/data/gfx/terrain/grass.png b/game/modules/boot/data/gfx/terrain/grass.png
new file mode 100644
index 0000000000000000000000000000000000000000..bf3598e27f7fcafb1f8b5c58eaed7e0db0195a13
GIT binary patch
literal 684
zcmV;d0#p5oP)<h;3K|Lk000e1NJLTq001BW001Be0ssI2{21+{00006bW%=J0RI60
z0RJ~w8+`x(0%1u+K~zYIeO5Vc!!QsWF@#|RMqn5$Qs^6bVjkf#e^bfAaABx$kz(l4
zXvu_yz-zDB*`=m(1;?!dK$%e&oD1@CFnO-HRg@V(+mw`!>H;5GGZ&*$Aezw~PF$+Y
zn{z&rX0j~p!QQ#-_H{G5d_+FB$<Bb}`8}8BowU2l0#i#`;$~eoFE;}&?_nwkUkVo4
z5JbQZt8B_6h!lRVTgbkYD*-oI<;^75JdIpZIHV*XCS!pDx|ulh19W-zfcRB<wW&~~
zq~$<v2JMc!^m>TlD1@TKOyxQ#F~aAi6h<)9<0FNQMGBC59U`eK^Tu7#|G5q@bf6}-
z3J*fwJ=g7sq4>Ag6;jQeOhEd4y5llNplKse{#M7lcw4`4y5Ri-heMm__;JVM-gZux
zwk$IahZu3n?MQcYGxzjz1pMnw@E_23Wqic+`4bg|A&9&Zxnzs}tJk(9=kI|!cM#T&
zs1aRd1j_j`;l)3lc?VY1o<mPQI!0(oor6ktuVqr0x>DT<?LoHB1=(dnqKHWVjSlr`
z9~J?C6q-zEzmg9fhC}TnNa?|-%c~dl&y%<QVLn|%9NUn2@hYqDJGdNbb2KJ!<Xv9`
ztRas(1&=(*9+0OhG;I%sJ~@$+Yw@SJ@BSW;bH)MmzDu`~II0&WG=qQuIxc!|=<BZ4
zLES&LeKJWE?O;^ru3f$+f9gUIE)RPcgobQ*Ruu|;%8q8BTJMo(qUWpL70+d&9Y@f+
zLbZPgud*Ru!%t%~pqV<4tCq9Q9PbAnLEZl}a!mStXZXXn#d(4eUo~8ui2VW`2wnHT
Syy9a30000<MNUMnLSTY>%{Z+9

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/terrain/grass_flower3.png b/game/modules/boot/data/gfx/terrain/grass_flower3.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e1738db36965626785124ac7b24dec2ebef132d
GIT binary patch
literal 1096
zcmV-O1h@N%P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1KmkPK~z{rg;%kv
z6G0Tc8=he4LJA8($PXxNDHcLX5iGJFV3GF;5&I|Z2UsM9V4D<zSOzS_&ISE}2ZCi_
zEd_-*XLir#?9HssBkX48&OPUzd*^0eHeK7%y7BYSzD)0!9e$YInwnkQ9Do1w%M5#9
zkHJ0aM{Tg~$3!RKC<P9i6cNl3c+3xM)F*<{&wzk3Bp@B96j6J=b6+Z2tdTUI0|H>i
zjeKH`5~~U%#x+fy&cP2pQ~~cA+<<_03UD2&f>(yAAP`AtT77-t`xybvmx5rPMai1*
za|Bf-wMINSC^2C!w9r&StkYqtE>dZsPY<Z6;JyiS;w4l<s)SdCPPO<HNYx-ARb`^l
zsewOsS|19aYNc#aYG{3AXhdTT2u(zZ(C)08gozXp5>2VgVEZCesR-(G&MM|pk0_5D
z)<E3%2vt|#qXO9ERnUmwP;CGVd;c5*Nfjf5$Zo&2Bm1>V>z(P^lh5tXN1i{org_yr
z)#lCJtS9JeL+!GQD?2h;=3J{(jh}r#+H6+YYPE{fn~m9Wd3s{5uG<}0d;cICbU{YV
z+5ldE3baMC<8cFkUr&#=URwkwh>|0CQJC=qrBZ2OhaEH`pC{G?i;0nHluc7vS(YIU
zRpg@4!ybf5Lj7ych$--qXaO?ch)PN9_oZ#OyMAj~E^I#E#_ygi>OtjKym$=R)740i
z6(Z4GEBK9<tvisxyxQTN!>5928100r0t$+eLGtaYi#!zE?-$U%BN67YPGIiCDpRR`
zK_VVQ-&%bKLlGhcXCyEO@a|bwi=f0do&XHggr0;Hk^UGesK3X70MdZLqgPc`0H_18
zqJQFqa2>Xnmu5cyY+g)F|69NuJ^i{kC9Zqh+0K^vm-ubHZl&-&U<lmhBuLXVrM<g<
zDptMd0`sgBg21jgZ2;J!Zb{`is=RgXiL?=)fa@ZJAI5CoL;{RlixKNF1%C0~bZK?d
zCGr|xS}8!JRRbrNU@BN)n^|T>9`@Ipke+2vz{?6ENOe+y>v?`6fSn-GjYZRvh=WB4
za^Wv3N83OeM4-T@$F04#VE#YR--y@?V2n-JoEp1)7r}Hy@Gu|2p;q`nt#5~oeVh-$
z{dIlxLh@+8uz?byLJtlwWFqfox~TCDK>(a>cl18s`+!y{Pef0|lW00%5Rf{-EDFyT
zoE|}T!n5Ck)F!BrOh;D>ni2y0oF^TG$^J$Jga7?g$u`PjdibFw#&hn;`(IezH+aLs
z-T?tj{3~bbkaq@Fvo9`h3*Vg6|G3Tws6(v>N|<t@w`H$FY9E563V#6<TB*(A>KmH?
O0000<MNUMnLSTaRB=Xb%

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/terrain/tree_alpha1.png b/game/modules/boot/data/gfx/terrain/tree_alpha1.png
new file mode 100644
index 0000000000000000000000000000000000000000..c81bfcdb5db734efc6d1ad3e8c88af742e93020d
GIT binary patch
literal 829
zcmV-D1H$}?P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igW5
z3J@Ega<O0l00O;9L_t(o!|j$oNE=}o#(&Y^C8uHuqM^`;R7ju&3DqH?sa8s{v{Tzb
zibLp-(z>~qP&zu7LI!aVx9;N5R)x3-Qko$FOK6trwWO42(nzk?A$*s+%f<XDC={P1
z$@hKadEV!J-tP`BaDj7%qn*Q(aknPE?`?MjP<emkI1>SrakrM38>RPT7J%cP_3HXU
zPCwI$7)Lu*$EF7WnDBZ4*geRT%DMnZem&G(X-ABsm8t=HPi8spSvQdiVu0|-Fwu~#
z@4s37L1ka99?F#(@;I9*+&#!M<$1zpevJvQhg8<3liHmX`@smLhsppHaBGc3G<6_6
zGHhBilBY9e0)EM~pU#v`zY9s}-yB%D@eqK`{2HmOi`eu4sjQ3ZqrX|qC^})lFOkla
zDJgO_1Hyg)Uk46|>Z2jq)PDhM4ul&*pf#A4ebv?pN3-y)>=cQHWK*B50tA_ne0d{B
zNs)066)7olLjlfa;fsdWS=lMp^*=n~s#`M#G~ky=Q>+n<byKkk<Ebr(O%LcZZxojJ
z_=|L=%+tF*Q?<c}Y6@W?DVYV>xZr5z0!qw{)>*&2QM&<+LPQt~NeSne;bQ7E1EONP
zacndJR#f&?`om@0k!+ZOTd&e=#RE)uJuGGvpql7lL^aKONs-x80AzEu2K0x8IJNaL
z?4Rq>w&DTZ`sc5Yh;>~h@#hNw!HBAlm=I;XkOF>*z3po6+s=S<rcZnOvahc1Q=h#Y
zKK`j&ZgfPnLO4_BNUIqziqLPw`9V|gtR!OI#iwztQ2^U}A@R92W2&vyi9KO=E7iCC
zMue|6ngUDrW>|gqflsnlBQl;l<w4Za!^i~7pS`#<Zco&N)QGP0ektu(!1$o7<-UCf
z;L7kN#s_8XOa;t8x~+eox*7Z@5p84X*?sN7waXe8_#f~W@?4mv3&a1-00000NkvXX
Hu0mjf!o7e|

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/terrain/tree_alpha2.png b/game/modules/boot/data/gfx/terrain/tree_alpha2.png
new file mode 100644
index 0000000000000000000000000000000000000000..231b4f39819ae076c5a086ccb0064e95900a3b96
GIT binary patch
literal 777
zcmV+k1NQuhP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igW5
z3okF{+6CSK00N0gL_t(o!|hi+YujKDek45g7Zh8uMFn0<p@^UgS^_SZ7z$n7-2__5
z&?$@OZ2kxR1071If(iytvPqRLS)C|}WI5y)bX5oWUY)EjTQQ|WZn1Ro``&ZUJ$J7J
zJlYQIWQ4H)8DW*R@~%L9{Gg)>2zeLTANPmi-gv(q2zi@8S$;17+~pXS?VzP>pFpi@
zaPoCc9a^IUFL1E%fqQ?)08T~-yQUu9j2r=kd|IQE`2W);03f{n4e3E8;8|;p4zxxG
z$NeERC8B+P>i~%8cb8)Tz+MwDjR?fEmz!xpDg!_i1AsL>g&V9uv3ipa0PI<OeeVNh
zOh_A1pJBv6Th+xq0r6J9q=_OBwX)W7mt(OxXM@bL9cT(LIRjd&@+|zg95#wIQ7g(k
zFF3WGro^S77Np>tnp8$V56ZLVI+&a#*K;Py^iVj6)`QP)9Z`F#Gf@u!2m5hw>WVTp
z3g-Y1Ox9L)v{j`13m=%2u(0(g)*78uaLxqJey^Dwj2Ot94RT)niT>`ZVWQ8)0Alli
zQ{GaLI1|bkC@cXD9ugaMgvS7J0UqqfzD>J9&QrfNJw;p9MQ}GrPCVXv{F(rnMjAv`
z8FDqyR`t}h^H$jt%|#;fg0wHI6>C|GxbS%2b9EO5<e(~PfK$D`F>PoX(X(~+)AhPP
zZxH2*kk9mUTb%P^^KV}h=YJ~Ob31-sbReYwShgeTOc}2hhdi54Zx3;E72xOfMP>pl
zVByP2>H&YLoPEz;*fZ+k>o+d|05?|wroS$6;r)?N!BPz51?Bc*b|(P{j|LG753x$G
z<vpVw9t{pLckhJndF#o)`7r4j^$-Bw4ZcW}eO3A&?Z2?U+$3bFGm0BZ00000NkvXX
Hu0mjf=v_*5

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/terrain/tree_alpha3.png b/game/modules/boot/data/gfx/terrain/tree_alpha3.png
new file mode 100644
index 0000000000000000000000000000000000000000..3cb5f05f8462385e8ec7d6ce2c445060971378de
GIT binary patch
literal 1016
zcmV<U0|)$xP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igW5
z3os$gI3`B`00VeQL_t(o!|j$mXd_n?g}<>J7)>)`2#j!yehfinz>pxB6cR$VF#&^%
zUDXRA5OB4yslt*rkjl+E5ErSG#$ZTcTL`&WY>~pfnw4a<i^T>ZHRCa1cT$Y*lg75R
zk~btp_BQkPm~-yA=f3;kL;T-En`QCFUc#%jI`k_R0B@eZ)Br+Xe&UTj&l2;~EV7=4
zy>#4WC%?((dq3kXIz&<~eSBau-vv<5vk=jy0WW4v9xpuv;HMYA0q}U~A)kKtt52k2
zDN?<<j@CA&CNVcjZn<BM`jS_jGR=mr$gHoL^y>Ohfr>>W<*I*3X=YYnV=v)}+{LU(
zv!UNwb9mfmeboe@*6L8qnv_oZLw{UcF}LFJ_Edw5t~NCR0k1k`&M&(v+p1G0XB5<X
zKoLtMU78JDT>*~v{!&CH5xCQY0@7^gu;kah+0Y?VR=_*?O{&o{Pf88ICXsY`wtEd+
z4>B{}2|l(2*3+=}V=*}-F$l?UD`Su|3d)eBlfGKhtLv<<nn49%ERnf!;5nlJz)pUX
zt&9->Kfmm<T{%!{q~kWltZ&Fj%H{CbC*&<UgkoVru`t9e@0|n$Ttc!JB@#)OoKavo
zYAHgsRtJD*yVq!K1As`%#anc^cN>byr0<1Dv!PRU$^mlH1(B4CneUR0+e!%uQQ|HY
z0tC`=o19TlKwB9<Be@E>{WFJJtE1Ylm^D@XMFF|L*H*lhG1xzINF-gBqZT=%KrTO2
zLu60KZNQ~;(pNj6Uw<E5N}{#LcSJyeTC1b_U1I;tujO{-K=~jYw@JrsYOM~t--lGz
zYmYu6l5!QW#H4n-(*xU;0}@F$-~)MHj#`0|c#96bx=yd|E7Pm%QycIWf$k4i+LKZv
zu%ij^sOioxy9#W5)eIPJG=#{cHk`j}@(FP1q>r>^v*8SCZ*zEj4fx<f<fidP%P^?~
z^EVYJfhXft%;ayk{<N#*JL>)6aUZR1p#i-yz@b?9p67v><;|@GRg>u_+pI`@({zEX
zW0p5*9*jK?2=lk6+O07x;9A>Y<03pBe8LQv?nE?TF9!<&mH1}iV|HKt83djJbow*l
z;74zszZ^)Z0awHC3nQR20>4*$``|P0;FqtxuT~bk_x+c4AMmxcFE~2-!%w>Xn%_@f
m{X3bDk^uN86!;MTdHfCT2kUjSedYxK0000<MNUMnLSTZ{7t)RZ

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/terrain/tree_alpha4.png b/game/modules/boot/data/gfx/terrain/tree_alpha4.png
new file mode 100644
index 0000000000000000000000000000000000000000..9c836a0e8d34748fdf5d171ae93e3ac2f1d647f3
GIT binary patch
literal 4267
zcmeHJUr5tY6h5<|n}5foO<c_dfkgB$A3~#`WagG+VLkZgC47@!g7vhQ{yjyHy;W2X
zp}sWmO~fDwvL}6r5F?lhi!@ly%nWSnes??D+1zx$2|amazkBcb-Fv?8e&^i#^WoLr
z?z-ycY9gu&_<en<_26fzRL@{2w4oYPu&=w5!m~$K)Sz;>r`tzK{JnfL_E>qWxBLS^
zqMAnhO!VYglX6zw4qWc4`doR`*>-wl>8XRrb~50*aJ}DZ^4KCjOlnG5X1`-iVqxrs
zHM@Q}W;mWXySlU<1NWbAptdGEg<Cf1!_o?^zdKCZq~tJ2!VqJCGjQu6KP~*7)U3lZ
zo4TEPm7wh}Dpv+bRFt;w+*tr;WAMqTIJ*qBC8t2{9thYyz#%`()=IR#T1V#NwT4nr
zatc78y~RnMV_Q1+v)^JG7>~t>B|`+Y04p^WB`biS00-D&1Urw@#L$RVq7BE5oSH<!
z@slbHD6yvkvg!w1gFw=t`3k_FUk8czD*PS=xvK(Fc7Su$0}PgxK2B>37V=+g(0;Cq
z_0{yzgtrKhq6%=)VJ(1QoB{ywafA|CB6^yBfDlr_R;(rpD!|~lX!MbDan+N~Gr$We
z0#IA)mR1A6s0Y|?HBnFjDLn#!2<M!43lcCM16-Qiz4U7(;7F$=hX8=_P6mhUFaU9%
z$7qob-Z{q7m{cJ$oRSOymK^~y(yRVhbX3PIb^^xV#tHWWjEfI_21j3-Bm)wfz+T`i
zvs6X~MIT2{=AYjKknaZeaa)i8zeLNx>?^b@0MwuR&QtVPF*7LAk#(R?LG0dd)42MS
zVuuXMvLc2A)|X2<aK)LVzH-+bsp^MYR(^U~>RRRjT5%_2YCykt+mn~>*6S`8mma7`
z23Rc~_Ii_Ny^S<HJxjhC7ft_)>W@%SZ~@5ixXmR1uOfj4yMsw!?MOeE#OTZlb+~Qx
zVE&VQo$c=ej!8Q&qV$3UrHDwmvQbk#r@M*<)ki22{gYB+{^QOK<uA$`8(tvSLj{+k
zmS&dMXu1q=#477QB1vMu{R0AJD}el8yV6Y2)eUl6%;Y<9Ds^lO=A<kF4E}oJD?Oi^
s+gBkQ<eNJkM5L!&6=aNq{(%DjU4izFM>j)5Jy8G$x_W)#&Kvjt0WdqQng9R*

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/terrain/tree_alpha5.png b/game/modules/boot/data/gfx/terrain/tree_alpha5.png
new file mode 100644
index 0000000000000000000000000000000000000000..b2a3635292abc63e852ecc41953eb2c8b09cc537
GIT binary patch
literal 4267
zcmeHJT}YEr7=Gu^rW2>GteJ|Epc7$KlwNeBGMO`6ArW;EL>EDHBiNO6)m;!>)LnQ{
zbRl#hR5u9;yQ~a_ku-%ULEZXc=F*v(uJ1W#@7LM(?FSRO@g4il&wI{!pYyyw-*@Mn
z&r@zaVkM$-Z?AhmYa8(|F>BAE;o()SF%1oPx@l~x?u#}sUp?b-QyjlX6Qd8bnbN`D
zOG89u2k<x1!x4uzX}Rg`@3G98>kpr_7rqR35mmN%-CgG|mYNzXKP_u3{;!zwHQ#rw
zDUP+V^{Ck5fATHwz1eIOWmB>a##=hK$a$!O96P5eTrf?6nOMB8)=YsH%cjoD)dF1P
z$8TC#+@#3VTHfIDUdRlby<pWq94G&GzrZ&!`jc@|U5#DzU%v~BHXk540kC0aAoz7f
z91b>Ac^fPg!;fzk^=XZzoNVL-fYSh?##OE#Y_mrw8j-hUgP=dMx~Z>;Nt`(W<ct9}
z?rU}l-{YpU{$ec{<xOE2(&9wU5v{FA5D3<UE}qR5IRS`M6A$>_*Gv?4PHQu$7(`4x
z`jg}HWUnkDYpD%G(H9+}j36?)fPIexK!3Y)J8@RBQMjPmaZu=RdrnhKsBVEvjF`v>
z00%Jr(fJLsHCPBOglQH7?V-?}6bHIKgK_9H0)TN&IpjS=r5oe5=sFr9;SUk+ik5Gm
z>E^uHFb4SMM3Q#+9?~v+FSouLNAMMhfyxLQmaB+RtTYjY3Y}CpWMx40JwSkoXHR1|
zC&||sCn8=1o}<-H(a$nFcr61<WyBBw2cVk!ILJs47hu5FD9ME3)Ih{Ot`QrXJG8xC
zpfiyMfayoE;cAE5Kc5RwC?LzOY5<2L?J$RSAr#S#L8ppQaY_S#4JrtX83_8Lk7b?b
zTraB-KBmH|og~_^Rt1wvJ@gPm08pg50gSM48CJ6ZI?z8kvm}<)*h_RK_~yJ{4Mf8%
z;Dv|*raeT(JgpU`zbU8&8;rv+3;Zp|vOKf@S&!C`0o4U6{dg1N_6WS$pmYUFFNCuI
zeRVEV@L?S!4FEna*uR_w{PyFB$41tn&jPl%DuyDzcv?g~1}gQeOalOgtG`MV4t(9X
z+N{*nQ7dkZbVFdB@-*;%QeVfIOuey~%kqU}2tYqw>)20}=~WE#sBBCz#wzs~12l`#
zjakQSP5``6ZBs$9E+2!uc2C+H9j^Gu^^SP=G3m1194g-?yVwci{eyk<eQAqYE%o#-
kAa-GXf6G1t`wZ+I1NZN}Z@zW(ZWm7U_W0am-B)h^0h#gkB>(^b

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/terrain/water_floor.png b/game/modules/boot/data/gfx/terrain/water_floor.png
new file mode 100644
index 0000000000000000000000000000000000000000..8a8cee416c5a551c1220ba3dc2effce6e6d25b8e
GIT binary patch
literal 154
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={W7>k44ofy`glX(f`a29w(7Bet#
z3xhBt!>l<HKtc8rPhVH|TP%{|DohLW<(z>+I-V|$As)xyo;74-FyLTNh~?(KdF<bN
uuNUmBCth`W>-TZ8Ff}?T2yn18>B?I~GV)CE4BQLU$KdJe=d#Wzp$P!&d?hRZ

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/gfx/terrain/water_floor_alpha.png b/game/modules/boot/data/gfx/terrain/water_floor_alpha.png
new file mode 100644
index 0000000000000000000000000000000000000000..c7f29d19c698962f1cf88c94c9592ac33be5a269
GIT binary patch
literal 177
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Y)RhkE)4%c
zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPio2;mo*kyt5Af1MuE{-7)hu@xa
zWMpt)VK7+N>U8TxapBPqH-&UoKR>=u{5T6L5Ubt8xWq^8!h4`*22WQ%mvv4FO#lT?
BFQfnf

literal 0
HcmV?d00001

diff --git a/game/modules/boot/data/rooms/pilar.lua b/game/modules/boot/data/rooms/pilar.lua
new file mode 100644
index 0000000000..337f27805e
--- /dev/null
+++ b/game/modules/boot/data/rooms/pilar.lua
@@ -0,0 +1,26 @@
+-- ToME - Tales of Middle-Earth
+-- 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 {
+[[#!!!!!!!!#]],
+[[!........!]],
+[[!...##...!]],
+[[!........!]],
+[[#!!!!!!!!#]],
+}
diff --git a/game/modules/boot/data/rooms/simple.lua b/game/modules/boot/data/rooms/simple.lua
new file mode 100644
index 0000000000..bcaf29ac19
--- /dev/null
+++ b/game/modules/boot/data/rooms/simple.lua
@@ -0,0 +1,37 @@
+-- ToME - Tales of Middle-Earth
+-- 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 function(gen, id)
+	local w = rng.range(5, 12)
+	local h = rng.range(5, 12)
+	return { name="simple"..w.."x"..h, w=w, h=h, generator = function(self, x, y, is_lit)
+		for i = 1, self.w do
+			for j = 1, self.h do
+				if i == 1 or i == self.w or j == 1 or j == self.h then
+					gen.map.room_map[i-1+x][j-1+y].can_open = true
+					gen.map(i-1+x, j-1+y, Map.TERRAIN, gen.grid_list[gen:resolve('#')])
+				else
+					gen.map.room_map[i-1+x][j-1+y].room = id
+					gen.map(i-1+x, j-1+y, Map.TERRAIN, gen.grid_list[gen:resolve('.')])
+				end
+				if is_lit then gen.map.lites(i-1+x, j-1+y, true) end
+			end
+		end
+	end}
+end
diff --git a/game/modules/boot/data/talents.lua b/game/modules/boot/data/talents.lua
new file mode 100644
index 0000000000..5d22407f2e
--- /dev/null
+++ b/game/modules/boot/data/talents.lua
@@ -0,0 +1,168 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+newTalentType{ type="misc/misc", name = "combat", description = "Combat techniques" }
+
+newTalent{
+	name = "Kick",
+	type = {"misc/misc", 1},
+	points = 1,
+	cooldown = 6,
+	power = 2,
+	range = 1,
+	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 math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end
+
+		target:knockback(self.x, self.y, 2 + self:getDex())
+		return true
+	end,
+	info = function(self, t)
+		return "Kick!"
+	end,
+}
+
+newTalent{
+	name = "Acid Spray",
+	type = {"misc/misc", 1},
+	points = 1,
+	cooldown = 6,
+	power = 2,
+	range = 6,
+	action = function(self, t)
+		local tg = {type="ball", range=self:getTalentRange(t), radius=1, talent=t}
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		self:project(tg, x, y, DamageType.ACID, 1 + self:getDex(), {type="acid"})
+		return true
+	end,
+	info = function(self, t)
+		return "Zshhhhhhhhh!"
+	end,
+}
+
+newTalent{
+	name = "Manathrust",
+	type = {"misc/misc", 1},
+	points = 5,
+	cooldown = 5,
+	range = 20,
+	direct_hit = true,
+	reflectable = true,
+	requires_target = true,
+	action = function(self, t)
+		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.ARCANE, rng.range(10, 20) * self:getTalentLevel(t))
+		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)), "mana_beam", {tx=x-self.x, ty=y-self.y})
+		return true
+	end,
+	info = function(self, t)
+		return "Zzttt"
+	end,
+}
+
+newTalent{
+	name = "Flame",
+	type = {"misc/misc",1},
+	points = 5,
+	cooldown = 5,
+	range = 20,
+	reflectable = true,
+	proj_speed = 20,
+	requires_target = true,
+	action = function(self, t)
+		local tg = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="bolt_fire", trail="firetrail"}}
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		self:projectile(tg, x, y, DamageType.FIRE,rng.range(10, 20) * self:getTalentLevel(t), {type="flame"})
+		return true
+	end,
+	info = function(self, t)
+		return "burnnn"
+	end,
+}
+
+newTalent{
+	name = "Fireflash",
+	type = {"misc/misc",3},
+	points = 5,
+	cooldown = 20,
+	range = 15,
+	proj_speed = 4,
+	direct_hit = true,
+	requires_target = true,
+	action = function(self, t)
+		local tg = {type="ball", range=self:getTalentRange(t), radius=1 + self:getTalentLevelRaw(t), friendlyfire=false, talent=t, display={particle="bolt_fire", trail="firetrail"}}
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		self:projectile(tg, x, y, DamageType.FIRE, rng.range(4, 8) * self:getTalentLevel(t), function(self, tg, x, y, grids)
+		game.level.map:particleEmitter(x, y, tg.radius, "fireflash", {radius=tg.radius, grids=grids, tx=x, ty=y})
+		end)
+		return true
+	end,
+	info = function(self, t)
+		return "Zoooshh!"
+	end,
+}
+
+newTalent{
+	name = "Lightning",
+	type = {"misc/misc", 1},
+	points = 5,
+	cooldown = 5,
+	range = 20,
+	direct_hit = true,
+	reflectable = true,
+	requires_target = true,
+	action = function(self, t)
+		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 = rng.range(15, 30) * self:getTalentLevel(t)
+		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})
+		return true
+	end,
+	info = function(self, t)
+		return "Zappp!"
+	end,
+}
+
+newTalent{
+	name = "Sunshield",
+	type = {"misc/misc", 3},
+	points = 5,
+	cooldown = 100,
+	range = 20,
+	direct_hit = true,
+	action = function(self, t)
+		self:setEffect(self.EFF_SUNSHIELD, 30, {})
+		return true
+	end,
+	info = function(self, t)
+		return "ooooh"
+	end,
+}
+
diff --git a/game/modules/boot/data/timed_effects.lua b/game/modules/boot/data/timed_effects.lua
new file mode 100644
index 0000000000..ac877b1ca0
--- /dev/null
+++ b/game/modules/boot/data/timed_effects.lua
@@ -0,0 +1,47 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+local Stats = require "engine.interface.ActorStats"
+local Particles = require "engine.Particles"
+
+newEffect{
+	name = "ACIDBURN",
+	desc = "Burning from acid",
+	type = "physical",
+	status = "detrimental",
+	parameters = { power=1 },
+	on_gain = function(self, err) return "#Target# is covered in acid!", "+Acid" end,
+	on_lose = function(self, err) return "#Target# is free from the acid.", "-Acid" end,
+	on_timeout = function(self, eff)
+		DamageType:get(DamageType.ACID).projector(eff.src or self, self.x, self.y, DamageType.ACID, eff.power)
+	end,
+}
+
+newEffect{
+	name = "SUNSHIELD",
+	desc = "Sunshield",
+	type = "magical",
+	status = "beneficial",
+	activate = function(self, eff)
+		eff.particle = self:addParticles(Particles.new("golden_shield", 1))
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle)
+	end,
+}
diff --git a/game/modules/boot/data/zones/dungeon/grids.lua b/game/modules/boot/data/zones/dungeon/grids.lua
new file mode 100644
index 0000000000..17d13d0604
--- /dev/null
+++ b/game/modules/boot/data/zones/dungeon/grids.lua
@@ -0,0 +1,22 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+load("/data/general/grids/basic.lua")
+load("/data/general/grids/forest.lua")
+load("/data/general/grids/water.lua")
diff --git a/game/modules/boot/data/zones/dungeon/npcs.lua b/game/modules/boot/data/zones/dungeon/npcs.lua
new file mode 100644
index 0000000000..3b3f983ec8
--- /dev/null
+++ b/game/modules/boot/data/zones/dungeon/npcs.lua
@@ -0,0 +1,22 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+load("/data/general/npcs/skeleton.lua")
+load("/data/general/npcs/canine.lua")
+load("/data/general/npcs/troll.lua")
diff --git a/game/modules/boot/data/zones/dungeon/objects.lua b/game/modules/boot/data/zones/dungeon/objects.lua
new file mode 100644
index 0000000000..cad1c5dde4
--- /dev/null
+++ b/game/modules/boot/data/zones/dungeon/objects.lua
@@ -0,0 +1,18 @@
+-- ToME - Tales of Middle-Earth
+-- 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
diff --git a/game/modules/boot/data/zones/dungeon/traps.lua b/game/modules/boot/data/zones/dungeon/traps.lua
new file mode 100644
index 0000000000..cad1c5dde4
--- /dev/null
+++ b/game/modules/boot/data/zones/dungeon/traps.lua
@@ -0,0 +1,18 @@
+-- ToME - Tales of Middle-Earth
+-- 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
diff --git a/game/modules/boot/data/zones/dungeon/zone.lua b/game/modules/boot/data/zones/dungeon/zone.lua
new file mode 100644
index 0000000000..9faab8139f
--- /dev/null
+++ b/game/modules/boot/data/zones/dungeon/zone.lua
@@ -0,0 +1,52 @@
+-- ToME - Tales of Middle-Earth
+-- 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 {
+	name = "Forest",
+	level_range = {1, 5},
+	level_scheme = "player",
+	max_level = 5,
+	decay = {300, 800},
+	actor_adjust_level = function(zone, level, e) return zone.base_level + level.level-1 + rng.range(-1,2) end,
+	width = 50, height = 50,
+--	all_remembered = true,
+	all_lited = true,
+	generator =  {
+		map = {
+			class = "engine.generator.map.Forest",
+			edge_entrances = {4,6},
+			zoom = 4,
+			sqrt_percent = 30,
+			noise = "fbm_perlin",
+			floor = function() if rng.chance(20) then return "FLOWER" else return "GRASS" end end,
+			wall = {"TREE","TREE2","TREE3","TREE4","TREE5","TREE6","TREE7","TREE8","TREE9","TREE10","TREE11","TREE12","TREE13","TREE14","TREE15","TREE16","TREE17","TREE18","TREE19","TREE20",},
+			up = "GRASS",
+			down = "GRASS",
+			do_ponds =  {
+				nb = {1, 2},
+				size = {w=25, h=25},
+				pond = {{0.6, "DEEP_WATER"}, {0.8, "SHALLOW_WATER"}},
+			},
+		},
+		actor = {
+			class = "engine.generator.actor.Random",
+			nb_npc = {20, 30},
+		},
+	},
+}
diff --git a/game/modules/boot/dialogs/LoadGame.lua b/game/modules/boot/dialogs/LoadGame.lua
new file mode 100644
index 0000000000..ffa730861c
--- /dev/null
+++ b/game/modules/boot/dialogs/LoadGame.lua
@@ -0,0 +1,111 @@
+-- TE4 - T-Engine 4
+-- 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
+
+require "engine.class"
+local Module = require "engine.Module"
+local Dialog = require "engine.ui.Dialog"
+local TreeList = require "engine.ui.TreeList"
+local Button = require "engine.ui.Button"
+local Textzone = require "engine.ui.Textzone"
+local Separator = require "engine.ui.Separator"
+local Savefile = require "engine.Savefile"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init()
+	Dialog.init(self, "Load Game", game.w, game.h)
+
+	local list = table.clone(game.save_list, true)
+
+	self.c_delete = Button.new{text="Delete", fct=function(text) self:deleteSave() end}
+	self.c_desc = Textzone.new{width=math.floor(self.iw / 3 * 2 - 10), height=self.ih - self.c_delete.h - 10, text=""}
+
+	self.tree = {}
+	local found = false
+	for i, mod in ipairs(list) do
+		local nodes = {}
+
+		for j, save in ipairs(mod.savefiles) do
+			save.fct = function()
+				Module:instanciate(mod, save.name, false)
+			end
+			save.mod = mod
+			save.zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text="#{bold}##GOLD#"..mod.long_name..": "..save.name.."#WHITE##{normal}#\n\n"..save.description}
+			table.insert(nodes, save)
+			found = true
+		end
+
+		if #nodes > 0 then
+			table.insert(self.tree, {
+				name="#{bold}##GOLD#"..mod.name.."#WHITE##{normal}#",
+				fct=function() end,
+				shown=true,
+				nodes=nodes,
+				zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text="#{bold}##GOLD#"..mod.long_name.."#WHITE##{normal}#\n\n"..mod.description}
+			})
+		end
+	end
+
+	self.c_tree = TreeList.new{width=math.floor(self.iw / 3 - 10), height=self.ih, scrollbar=true, columns={
+		{width=100, display_prop="name"},
+	}, tree=self.tree,
+		fct=function(item, sel, v) end,
+		select=function(item, sel) self:select(item) end,
+	}
+
+	self:loadUI{
+		{left=0, top=0, ui=self.c_tree},
+		{right=0, top=0, ui=self.c_desc},
+		{right=0, bottom=0, ui=self.c_delete},
+		{left=self.c_tree.w + 5, top=5, ui=Separator.new{dir="horizontal", size=self.ih - 10}},
+	}
+	self:setFocus(self.c_tree)
+	self:setupUI()
+
+	self.key:addBinds{
+		EXIT = function() game:unregisterDialog(self) end,
+	}
+end
+
+function _M:select(item)
+	if item and self.uis[2] then
+		self.uis[2].ui = item.zone
+		self.cur_sel = item
+	end
+end
+
+function _M:deleteSave()
+	if not self.cur_sel then return end
+
+	Dialog:yesnoPopup("Delete savefile", "Really delete #{bold}##GOLD#"..self.cur_sel.name.."#WHITE##{normal}#", function(ret)
+		if ret then
+			local base = Module:setupWrite(self.cur_sel.mod)
+			local save = Savefile.new(self.cur_sel.name)
+			save:delete()
+			save:close()
+			fs.umount(base)
+
+			game.save_list = Module:listSavefiles()
+
+			local d = new()
+			d.__showup = false
+			game:replaceDialog(self, d)
+		end
+	end, "Delete", "Cancel")
+end
diff --git a/game/modules/boot/dialogs/MainMenu.lua b/game/modules/boot/dialogs/MainMenu.lua
new file mode 100644
index 0000000000..b55c663801
--- /dev/null
+++ b/game/modules/boot/dialogs/MainMenu.lua
@@ -0,0 +1,59 @@
+-- TE4 - T-Engine 4
+-- 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
+
+require "engine.class"
+local Dialog = require "engine.ui.Dialog"
+local List = require "engine.ui.List"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init()
+	Dialog.init(self, "Main Menu", 300, 400, 450, 50)
+
+	self.list = {
+		{name="New Game", fct=function() game:registerDialog(require("mod.dialogs.NewGame").new()) end},
+		{name="Load Game", fct=function() game:registerDialog(require("mod.dialogs.LoadGame").new()) end},
+		{name="Player Profile", fct=function() game:registerDialog(require("mod.dialogs.Profile").new()) end},
+--		{name="Install Module", fct=function() end},
+		{name="Options", fct=function()
+			local menu menu = require("engine.dialogs.GameMenu").new{
+				"resume",
+				"keybinds_all",
+				"video",
+				"sound",
+			}
+			game:registerDialog(menu)
+		end},
+		{name="Exit", fct=function() game:onQuit() end},
+	}
+
+	self.c_list = List.new{width=self.iw, nb_items=#self.list, list=self.list, fct=function(item) end, font={"/data/font/VeraBd.ttf", 16}}
+
+	self:loadUI{
+		{left=0, top=0, ui=self.c_list},
+	}
+	self:setupUI(false, true)
+end
+
+function _M:on_recover_focus()
+	game:unregisterDialog(self)
+	local d = new()
+	d.__showup = false
+	game:registerDialog(d)
+end
diff --git a/game/modules/boot/dialogs/NewGame.lua b/game/modules/boot/dialogs/NewGame.lua
new file mode 100644
index 0000000000..c5771f4a25
--- /dev/null
+++ b/game/modules/boot/dialogs/NewGame.lua
@@ -0,0 +1,69 @@
+-- TE4 - T-Engine 4
+-- 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
+
+require "engine.class"
+local Module = require "engine.Module"
+local Dialog = require "engine.ui.Dialog"
+local ListColumns = require "engine.ui.ListColumns"
+local Textzone = require "engine.ui.Textzone"
+local Separator = require "engine.ui.Separator"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init()
+	Dialog.init(self, "New Game", game.w, game.h)
+
+	self.list = table.clone(game.mod_list, true)
+
+	self.c_desc = Textzone.new{width=math.floor(self.iw / 3 * 2 - 10), height=self.ih, text=""}
+
+	for i, mod in ipairs(self.list) do
+		mod.name = "#{bold}##GOLD#"..mod.name.."#{normal}##WHITE#"
+		mod.fct = function(mod)
+			game:registerDialog(require('engine.dialogs.GetText').new("Enter your character's name", "Name", 2, 25, function(text)
+				Module:instanciate(mod, text, true)
+			end))
+		end
+		mod.version_txt = ("%d.%d.%d"):format(mod.version[1], mod.version[2], mod.version[3])
+		mod.zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text="#{bold}##GOLD#"..mod.long_name.."#WHITE##{normal}#\n\n"..mod.description}
+	end
+
+	self.c_list = ListColumns.new{width=math.floor(self.iw / 3 - 10), height=self.ih - 10, scrollbar=true, columns={
+		{name="Game Module", width=80, display_prop="name"},
+		{name="Version", width=20, display_prop="version_txt"},
+	}, list=self.list, fct=function(item) end, select=function(item, sel) self:select(item) end}
+
+	self:loadUI{
+		{left=0, top=0, ui=self.c_list},
+		{right=0, top=0, ui=self.c_desc},
+		{left=self.c_list.w + 5, top=5, ui=Separator.new{dir="horizontal", size=self.ih - 10}},
+	}
+	self:setFocus(self.c_list)
+	self:setupUI()
+
+	self.key:addBinds{
+		EXIT = function() game:unregisterDialog(self) end,
+	}
+end
+
+function _M:select(item)
+	if item and self.uis[2] then
+		self.uis[2].ui = item.zone
+	end
+end
diff --git a/game/modules/boot/dialogs/Profile.lua b/game/modules/boot/dialogs/Profile.lua
new file mode 100644
index 0000000000..154ba65f67
--- /dev/null
+++ b/game/modules/boot/dialogs/Profile.lua
@@ -0,0 +1,86 @@
+-- TE4 - T-Engine 4
+-- 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
+
+require "engine.class"
+local Module = require "engine.Module"
+local Dialog = require "engine.ui.Dialog"
+local List = require "engine.ui.List"
+local Textzone = require "engine.ui.Textzone"
+local Separator = require "engine.ui.Separator"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init()
+	Dialog.init(self, "Player Profile", 400, 200)
+
+	self.c_desc = Textzone.new{width=300, height=self.ih, text=""}
+
+	self.list = {}
+	if profile.auth then
+		self.list[#self.list+1] = {name="Logout", fct=function()
+			Dialog:yesnoPopup("You are logged in", "Do you want to log out?", function(ret)
+				if ret then
+					profile:logOut()
+					game:checkLogged()
+				end
+			end, "Log out", "Cancel")
+		end}
+	else
+		self.list[#self.list+1] = {name="Login", fct=function()
+			local dialogdef = {}
+			dialogdef.fct = function(login) self:setPlayerLogin(login) end
+			dialogdef.name = "login"
+			dialogdef.justlogin = true
+			game:registerDialog(require('mod.dialogs.ProfileLogin').new(dialogdef, game.profile_help_text))
+		end}
+		self.list[#self.list+1] = {name="Create Account", fct=function()
+			local dialogdef = {}
+			dialogdef.fct = function(login) self:setPlayerLogin(login) end
+			dialogdef.name = "creation"
+			dialogdef.justlogin = false
+			game:registerDialog(require('mod.dialogs.ProfileLogin').new(dialogdef, game.profile_help_text))
+		end}
+	end
+
+	self.c_list = List.new{width=150, nb_items=#self.list, list=self.list, fct=function(item) end}
+
+	self:loadUI{
+		{left=0, top=0, ui=self.c_list},
+		{right=0, top=0, ui=self.c_desc},
+		{left=self.c_list.w + 5, top=5, ui=Separator.new{dir="horizontal", size=self.ih - 10}},
+	}
+	self:setupUI(true, true)
+
+	self.key:addBinds{
+		EXIT = function() game:unregisterDialog(self) end,
+	}
+end
+
+function _M:select(item)
+	if item and self.uis[2] then
+--		self.uis[2].ui = item.zone
+	end
+end
+
+function _M:on_recover_focus()
+	game:unregisterDialog(self)
+	local d = new()
+	d.__showup = false
+	game:registerDialog(d)
+end
diff --git a/game/modules/boot/dialogs/ProfileLogin.lua b/game/modules/boot/dialogs/ProfileLogin.lua
new file mode 100644
index 0000000000..fe3195cff3
--- /dev/null
+++ b/game/modules/boot/dialogs/ProfileLogin.lua
@@ -0,0 +1,85 @@
+-- TE4 - T-Engine 4
+-- 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
+
+require "engine.class"
+local Dialog = require "engine.ui.Dialog"
+local Button = require "engine.ui.Button"
+local Textbox = require "engine.ui.Textbox"
+local Textzone = require "engine.ui.Textzone"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init(dialogdef, profile_help_text)
+	Dialog.init(self, "Online profile "..dialogdef.name, 500, 400)
+	self.profile_help_text = profile_help_text
+	self.dialogdef = dialogdef
+	self.alpha = 230
+	self.justlogin = dialogdef.justlogin
+
+	self.c_desc = Textzone.new{width=math.floor(self.iw - 10), auto_height=true, text=self.profile_help_text}
+
+	if self.justlogin then
+		self.c_login = Textbox.new{title="Login: ", text="", chars=30, max_len=20, fct=function(text) self:okclick() end}
+		self.c_pass = Textbox.new{title="Password: ", text="", chars=30, max_len=20, hide=true, fct=function(text) self:okclick() end}
+		local ok = require("engine.ui.Button").new{text="Login", fct=function() self:okclick() end}
+		local cancel = require("engine.ui.Button").new{text="Cancel", fct=function() self:cancelclick() end}
+
+		self:loadUI{
+			{left=0, top=0, ui=self.c_desc},
+			{left=0, top=self.c_desc.h, ui=self.c_login},
+			{left=0, top=self.c_desc.h+self.c_login.h+5, ui=self.c_pass},
+			{left=0, bottom=0, ui=ok},
+			{right=0, bottom=0, ui=cancel},
+		}
+		self:setFocus(self.c_login)
+	else
+		self.c_login = Textbox.new{title="Login: ", text="", chars=30, max_len=20, fct=function(text) self:okclick() end}
+		self.c_pass = Textbox.new{title="Password: ", text="", chars=30, max_len=20, hide=true, fct=function(text) self:okclick() end}
+		self.c_email = Textbox.new{title="Email: ", text="", chars=30, max_len=60, fct=function(text) self:okclick() end}
+		self.c_name = Textbox.new{title="Name: ", text="", chars=30, max_len=60, fct=function(text) self:okclick() end}
+		local ok = require("engine.ui.Button").new{text="Create", fct=function() self:okclick() end}
+		local cancel = require("engine.ui.Button").new{text="Cancel", fct=function() self:cancelclick() end}
+
+		self:loadUI{
+			{left=0, top=0, ui=self.c_desc},
+			{left=0, top=self.c_desc.h, ui=self.c_login},
+			{left=0, top=self.c_desc.h+self.c_login.h+5, ui=self.c_pass},
+			{left=0, top=self.c_desc.h+self.c_login.h+self.c_pass.h+10, ui=self.c_email},
+			{left=0, top=self.c_desc.h+self.c_login.h+self.c_pass.h+self.c_email.h+15, ui=self.c_name},
+			{left=0, bottom=0, ui=ok},
+			{right=0, bottom=0, ui=cancel},
+		}
+		self:setFocus(self.c_login)
+	end
+	self:setupUI(true, true)
+
+	self.key:addBinds{
+		EXIT = function() game:unregisterDialog(self) end,
+	}
+end
+
+
+function _M:okclick()
+	game:unregisterDialog(self)
+	game:createProfile({login=self.c_login.text, pass=self.c_pass.text, email=self.c_email and self.c_email.text, name=self.c_name and self.c_name.text})
+end
+
+function _M:cancelclick()
+	self.key:triggerVirtual("EXIT")
+end
diff --git a/game/modules/boot/init.lua b/game/modules/boot/init.lua
new file mode 100644
index 0000000000..47c000f7a8
--- /dev/null
+++ b/game/modules/boot/init.lua
@@ -0,0 +1,30 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+name = "Boot"
+long_name = "Boot for T-Engine4"
+short_name = "boot"
+author = { "DarkGod", "darkgod@te4.org" }
+homepage = "http://te4.org/"
+version = {1,0,0}
+engine = {0,9,13}
+description = [[
+Bootmenu!
+]]
+starter = "mod.load"
diff --git a/game/modules/boot/load.lua b/game/modules/boot/load.lua
new file mode 100644
index 0000000000..9ad039df44
--- /dev/null
+++ b/game/modules/boot/load.lua
@@ -0,0 +1,64 @@
+-- ToME - Tales of Middle-Earth
+-- 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
+
+-- This file loads the game module, and loads data
+local KeyBind = require "engine.KeyBind"
+local DamageType = require "engine.DamageType"
+local ActorStats = require "engine.interface.ActorStats"
+local ActorResource = require "engine.interface.ActorResource"
+local ActorTalents = require "engine.interface.ActorTalents"
+local ActorAI = require "engine.interface.ActorAI"
+local ActorLevel = require "engine.interface.ActorLevel"
+local ActorTemporaryEffects = require "engine.interface.ActorTemporaryEffects"
+local Birther = require "engine.Birther"
+
+local n = core.noise.new(2)
+_2DNoise = n:makeTexture2D(64, 64)
+
+-- Usefull keybinds
+KeyBind:load("move,hotkeys,inventory,actions,interface,debug")
+
+-- Damage types
+DamageType:loadDefinition("/data/damage_types.lua")
+
+-- Talents
+ActorTalents:loadDefinition("/data/talents.lua")
+
+-- Timed Effects
+ActorTemporaryEffects:loadDefinition("/data/timed_effects.lua")
+
+-- Actor resources
+ActorResource:defineResource("Power", "power", nil, "power_regen", "Power represent your ability to use special talents.")
+
+-- Actor stats
+ActorStats:defineStat("Strength",	"str", 10, 1, 100, "Strength defines your character's ability to apply physical force. It increases your melee damage, damage with heavy weapons, your chance to resist physical effects, and carrying capacity.")
+ActorStats:defineStat("Dexterity",	"dex", 10, 1, 100, "Dexterity defines your character's ability to be agile and alert. It increases your chance to hit, your ability to avoid attacks and your damage with light weapons.")
+ActorStats:defineStat("Constitution",	"con", 10, 1, 100, "Constitution defines your character's ability to withstand and resist damage. It increases your maximun life and physical resistance.")
+
+-- Actor AIs
+ActorAI:loadDefinition("/engine/ai/")
+ActorAI:loadDefinition("/mod/ai/")
+
+-- Birther descriptor
+Birther:loadDefinition("/data/birth/descriptors.lua")
+
+-- Switch to realtime, with 10 ticks per second
+core.game.setRealtime(8)
+
+return {require "mod.class.Game" }
diff --git a/game/modules/tome/data/general/objects/world-artifacts.lua b/game/modules/tome/data/general/objects/world-artifacts.lua
index b6070fe171..a6099e4530 100644
--- a/game/modules/tome/data/general/objects/world-artifacts.lua
+++ b/game/modules/tome/data/general/objects/world-artifacts.lua
@@ -713,7 +713,7 @@ newEntity{ base = "BASE_STAFF", define_as = "VOICE_SARUMAN",
 }
 
 newEntity{ base = "BASE_WAND",
-	unided_name = "glowing wand",
+	unided_name = "glowing rod",
 	name = "Gwai's Burninator", color=colors.LIGHT_RED, unique=true,
 	cost = 50,
 	rarity = 220,
diff --git a/src/core_lua.c b/src/core_lua.c
index 4973e27216..bbb83c7982 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -409,9 +409,26 @@ static int lua_exit_engine(lua_State *L)
 	exit_engine = TRUE;
 	return 0;
 }
-extern bool reboot_lua;
+extern bool reboot_lua, reboot_new;
+extern char *reboot_engine, *reboot_engine_version, *reboot_module, *reboot_name;
 static int lua_reboot_lua(lua_State *L)
 {
+	if (reboot_engine) free(reboot_engine);
+	if (reboot_engine_version) free(reboot_engine_version);
+	if (reboot_module) free(reboot_module);
+	if (reboot_name) free(reboot_name);
+
+	reboot_engine = (char *)luaL_checkstring(L, 1);
+	reboot_engine_version = (char *)luaL_checkstring(L, 2);
+	reboot_module = (char *)luaL_checkstring(L, 3);
+	reboot_name = (char *)luaL_checkstring(L, 4);
+	reboot_new = lua_toboolean(L, 5);
+
+	if (reboot_engine) reboot_engine = strdup(reboot_engine);
+	if (reboot_engine_version) reboot_engine_version = strdup(reboot_engine_version);
+	if (reboot_module) reboot_module = strdup(reboot_module);
+	if (reboot_name) reboot_name = strdup(reboot_name);
+
 	reboot_lua = TRUE;
 	return 0;
 }
diff --git a/src/main.c b/src/main.c
index f0ff461d0d..4c3e534a0b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -48,7 +48,8 @@ lua_State *L = NULL;
 int current_mousehandler = LUA_NOREF;
 int current_keyhandler = LUA_NOREF;
 int current_game = LUA_NOREF;
-bool reboot_lua = FALSE;
+bool reboot_lua = FALSE, reboot_new = FALSE;
+char *reboot_engine = NULL, *reboot_engine_version = NULL, *reboot_module = NULL, *reboot_name = NULL;
 bool exit_engine = FALSE;
 bool no_sound = FALSE;
 bool isActive = TRUE;
@@ -547,6 +548,7 @@ void setupRealtime(float freq)
 	if (!freq)
 	{
 		if (realtime_timer_id) SDL_RemoveTimer(realtime_timer_id);
+		realtime_timer_id = NULL;
 		printf("[ENGINE] Switching to turn based\n");
 	}
 	else
@@ -691,6 +693,9 @@ void boot_lua(int state, bool rebooting, int argc, char *argv[])
 		/* When rebooting we destroy the lua state to free memory and we reset physfs */
 		if (rebooting)
 		{
+			current_mousehandler = LUA_NOREF;
+			current_keyhandler = LUA_NOREF;
+			current_game = LUA_NOREF;
 			lua_close(L);
 			PHYSFS_deinit();
 		}
@@ -768,7 +773,12 @@ void boot_lua(int state, bool rebooting, int argc, char *argv[])
 
 		// And run the lua engine scripts
 		luaL_loadfile(L, "/loader/init.lua");
-		docall(L, 0, 0);
+		if (reboot_engine) lua_pushstring(L, reboot_engine); else lua_pushnil(L);
+		if (reboot_engine_version) lua_pushstring(L, reboot_engine_version); else lua_pushnil(L);
+		if (reboot_module) lua_pushstring(L, reboot_module); else lua_pushnil(L);
+		if (reboot_name) lua_pushstring(L, reboot_name); else lua_pushnil(L);
+		lua_pushboolean(L, reboot_new);
+		docall(L, 5, 0);
 	}
 }
 
@@ -792,6 +802,16 @@ int main(int argc, char *argv[])
 	// Change to line buffering
 	setvbuf(stdout, (char *) NULL, _IOLBF, 0);
 
+	// Parse arguments
+	int i;
+	for (i = 1; i < argc; i++)
+	{
+		char *arg = argv[i];
+		if (!strncmp(arg, "-M", 2)) reboot_module = strdup(arg+2);
+		if (!strncmp(arg, "-u", 2)) reboot_name = strdup(arg+2);
+		if (!strncmp(arg, "-n", 2)) reboot_new = TRUE;
+	}
+
 	boot_lua(1, FALSE, argc, argv);
 
 	// initialize engine and set up resolution and depth
@@ -928,6 +948,8 @@ int main(int argc, char *argv[])
 		/* Reboot the lua engine */
 		if (reboot_lua)
 		{
+			tickPaused = FALSE;
+			setupRealtime(0);
 			boot_lua(1, TRUE, argc, argv);
 			boot_lua(2, TRUE, argc, argv);
 		}
-- 
GitLab