diff --git a/game/engine/Dialog.lua b/game/engine/Dialog.lua
index 9d11b14ec7db54cbbc005e1ab068bf691ad1cbe4..b0d69b75159e0f9e276e160246e3fe30d4693e6b 100644
--- a/game/engine/Dialog.lua
+++ b/game/engine/Dialog.lua
@@ -96,7 +96,7 @@ function _M:init(title, w, h, x, y, alpha, font)
 	self.iw, self.ih = w - 2 * 5, h - 8 - 16 - 3
 	self.internal_surface = core.display.newSurface(self.iw, self.ih)
 	self.surface:alpha(alpha or 220)
-	self.texture = self.surface:glTexture()
+	self.texture, self.texture_w, self.texture_h = self.surface:glTexture()
 	self.changed = true
 end
 
@@ -123,35 +123,42 @@ function _M:display()
 
 	local tw, th = self.font:size(self.title)
 	s:drawColorStringBlended(self.font, self.title, (self.w - tw) / 2, 4, 255,255,255)
-	
+
 	self.internal_surface:erase()
 	self:drawDialog(self.internal_surface)
 	s:merge(self.internal_surface, 5, 20 + 3)
 
+	-- Update texture
+	self.surface:updateTexture(self.texture)
+
 	return self.surface
 end
 
-function _M:addControl(control)			
+function _M:toScreen(x, y)
+	self.texture:toScreenFull(x, y, self.w, self.h, self.texture_w, self.texture_h)
+end
+
+function _M:addControl(control)
 	control.tabindex = self.tabindex
-	self.tabindex = self.tabindex + 1	
-	self.controls[control.name] = control	
+	self.tabindex = self.tabindex + 1
+	self.controls[control.name] = control
 	table.sort(self.controls, function(a,b) return a.tabindex<b.tabindex end)
 end
 
 function _M:changeFocus(up)
-    local add = 1
+	local add = 1
 	if not up then add = -1 end
 	self.currenttabindex = self.currenttabindex + add
-	if (self.currenttabindex==self.tabindex) then self.currenttabindex = 0 end	
+	if (self.currenttabindex==self.tabindex) then self.currenttabindex = 0 end
 	if self.currenttabindex==-1 then self.currenttabindex=self.tabindex-1 end
 	local name = ""
 	for i, cntrl in pairs(self.controls) do
-		if cntrl.tabindex==self.currenttabindex then 
+		if cntrl.tabindex==self.currenttabindex then
 			if self.controls[self.state] and self.controls[self.state].unFocus then self.controls[self.state]:unFocus() end
-			cntrl.focused=true 
-			name=i 
+			cntrl.focused=true
+			name=i
 		end
-	end	
+	end
 	return name
 end
 
@@ -161,29 +168,25 @@ function _M:focusControl(focusOn)
 	for i, cntrl in pairs(self.controls) do
 		if i==focusOn then cntrl.focused=true self.state=i self.currenttabindex=cntrl.tabindex end
 		if i==oldstate and cntrl.unFocus then cntrl:unFocus() end
-	end		
+	end
 end
 
 
 function _M:databind()
-	local result = { } 
-	for i, cntrl in pairs(self.controls or { }) do		
+	local result = { }
+	for i, cntrl in pairs(self.controls or { }) do
 	    if cntrl.type and cntrl.type=="TextBox" then
 			result[cntrl.name] = cntrl.text
 		end
-	end		
+	end
 	return result
 end
 
 
-function _M:drawControls(s)	
-	for i, cntrl in pairs(self.controls or { }) do		
+function _M:drawControls(s)
+	for i, cntrl in pairs(self.controls or { }) do
 	    cntrl:drawControl(s)
-	end	
-end
-
-function _M:toScreen(x,y)
-	self.surface:toScreenWithTexture(self.texture,x,y)
+	end
 end
 
 function _M:drawDialog(s)
diff --git a/game/modules/tome/class/interface/Archery.lua b/game/modules/tome/class/interface/Archery.lua
new file mode 100644
index 0000000000000000000000000000000000000000..61a93581aba350f33b4ab3e6cc04afba35b011b7
--- /dev/null
+++ b/game/modules/tome/class/interface/Archery.lua
@@ -0,0 +1,201 @@
+-- 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 Chat = require "engine.Chat"
+local Target = require "engine.Target"
+local Talents = require "engine.interface.ActorTalents"
+
+--- Interface to add ToME archery combat system
+module(..., package.seeall, class.make)
+
+--- Look for possible archery targets
+-- Take care of removing enough ammo
+function _M:archeryAcquireTargets(tg, params)
+	local weapon, ammo = self:hasArcheryWeapon()
+	if not weapon then
+		game.logPlayer(self, "You must wield a bow or a sling (%s)!", ammo)
+		return nil
+	end
+	params = params or {}
+
+	print("[ARCHERY AQUIRE TARGETS WITH]", weapon.name, ammo.name)
+	local realweapon = weapon
+	weapon = weapon.combat
+
+	local tg = tg or {type="bolt"}
+
+	if not tg.range then tg.range=weapon.range or 10 end
+	tg.display = tg.display or {display='/'}
+	tg.speed = tg.speed or 20
+	local x, y = self:getTarget(tg)
+	if not x or not y then return nil end
+
+	-- Find targets to know how many ammo we use
+	local targets = {}
+	if params.one_shot then
+		local ammo = self:removeObject(self:getInven("QUIVER"), 1)
+		if ammo then
+			targets = {{x=x, y=y, ammo=ammo.combat}}
+		end
+	else
+		local limit_shots = params.limit_shots
+
+		self:project(tg, x, y, function(tx, ty)
+			local target = game.level.map(tx, ty, game.level.map.ACTOR)
+			if not target then return end
+			if tx == self.x and ty == self.y then return end
+
+			if limit_shots then
+				if limit_shots <= 0 then return end
+				limit_shots = limit_shots - 1
+			end
+
+			for i = 1, params.multishots or 1 do
+				local ammo = self:removeObject(self:getInven("QUIVER"), 1)
+				if ammo then targets[#targets+1] = {x=tx, y=ty, ammo=ammo.combat}
+				else break end
+			end
+		end)
+	end
+
+	if #targets > 0 then
+		local sound = weapon.sound
+
+		local speed = self:combatSpeed(weapon)
+		print("[SHOOT] speed", speed or 1, "=>", game.energy_to_act * (speed or 1))
+		self:useEnergy(game.energy_to_act * (speed or 1))
+
+		if sound then game:playSoundNear(targets[1], sound) end
+
+		if ammo:getNumber() < 10 or ammo:getNumber() == 50 or ammo:getNumber() == 40 or ammo:getNumber() == 25 then
+			game.logPlayer(self, "You only have %d %s left!", ammo:getNumber(), ammo.name)
+		end
+
+		return targets
+	else
+		return nil
+	end
+end
+
+--- Archery projectile code
+local function archery_projectile(tx, ty, tg, self)
+	local weapon, ammo = tg.archery.weapon, tg.archery.ammo
+
+	local target = game.level.map(tx, ty, game.level.map.ACTOR)
+	if not target then return end
+
+	local talent = self:getTalentFromId(tg.talent_id)
+
+	local damtype = tg.archery.damtype or ammo.damtype or DamageType.PHYSICAL
+	local mult = tg.archery.mult or 1
+
+	-- Does the blow connect? yes .. complex :/
+	local atk, def = self:combatAttack(weapon), target:combatDefenseRanged()
+	local dam, apr, armor = self:combatDamage(ammo), self:combatAPR(ammo), target:combatArmor()
+	print("[ATTACK ARCHERY] to ", target.name, " :: ", dam, apr, armor, "::", mult)
+	if not self:canSee(target) then atk = atk / 3 end
+
+	-- If hit is over 0 it connects, if it is 0 we still have 50% chance
+	local hitted = false
+	if self:checkHit(atk, def) then
+		apr = apr + (tg.archery.apr or 0)
+		print("[ATTACK ARCHERY] raw dam", dam, "versus", armor, "with APR", apr)
+
+		local dam = math.max(0, dam - math.max(0, armor - apr))
+		local damrange = self:combatDamageRange(ammo)
+		dam = rng.range(dam, dam * damrange)
+		print("[ATTACK ARCHERY] after range", dam)
+
+		local crit
+		if tg.archery.crit_chance then self.combat_physcrit = self.combat_physcrit + tg.archery.crit_chance end
+		dam, crit = self:physicalCrit(dam, ammo, target)
+		if tg.archery.crit_chance then self.combat_physcrit = self.combat_physcrit - tg.archery.crit_chance end
+		print("[ATTACK ARCHERY] after crit", dam)
+
+		dam = dam * mult
+		print("[ATTACK ARCHERY] after mult", dam)
+
+		if crit then game.logSeen(self, "%s performs a critical strike!", self.name:capitalize()) end
+		DamageType:get(damtype).projector(self, target.x, target.y, damtype, math.max(0, dam))
+		game.level.map:particleEmitter(target.x, target.y, 1, "archery")
+		hitted = true
+
+		if talent.archery_onhit then talent.archery_onhit(self, talent, target, target.x, target.y) end
+	else
+		local srcname = game.level.map.seens(self.x, self.y) and self.name:capitalize() or "Something"
+		game.logSeen(target, "%s misses %s.", srcname, target.name)
+	end
+
+	-- Ranged project
+	if hitted and not target.dead then for typ, dam in pairs(self.ranged_project) do
+		if dam > 0 then
+			DamageType:get(typ).projector(self, target.x, target.y, typ, dam)
+		end
+	end end
+
+	-- Regen on being hit
+	if hitted and not target.dead and target:attr("stamina_regen_on_hit") then target:incStamina(target.stamina_regen_on_hit) end
+	if hitted and not target.dead and target:attr("mana_regen_on_hit") then target:incMana(target.mana_regen_on_hit) end
+end
+
+--- Shoot at one target
+function _M:archeryShoot(targets, talent, tg, params)
+	local weapon, ammo = self:hasArcheryWeapon()
+	if not weapon then
+		game.logPlayer(self, "You must wield a bow or a sling (%s)!", ammo)
+		return nil
+	end
+
+	print("[SHOOT WITH]", weapon.name, ammo.name)
+	local realweapon = weapon
+	weapon = weapon.combat
+
+	local tg = tg or {type="bolt"}
+	tg.talent = tg.talent or talent
+
+	if not tg.range then tg.range=weapon.range or 10 end
+	tg.display = tg.display or {display='/'}
+	tg.speed = tg.speed or 20
+	tg.archery = params or {}
+	tg.archery.weapon = weapon
+	for i = 1, #targets do
+		local tg = table.clone(tg)
+		tg.archery.ammo = targets[i].ammo
+		print("******........ firing target", targets[i].x, targets[i].y, "from", self.x, self.y)
+		self:projectile(tg, targets[i].x, targets[i].y, archery_projectile)
+	end
+end
+
+--- Check if the actor has a bow or sling and corresponding ammo
+function _M:hasArcheryWeapon()
+	if not self:getInven("MAINHAND") then return nil, "no shooter" end
+	if not self:getInven("QUIVER") then return nil, "no ammo" end
+	local weapon = self:getInven("MAINHAND")[1]
+	local ammo = self:getInven("QUIVER")[1]
+	if not weapon or not weapon.archery then
+		return nil, "no shooter"
+	end
+	if not ammo or not ammo.archery_ammo or weapon.archery ~= ammo.archery_ammo then
+		return nil, "bad or no ammo"
+	end
+	return weapon, ammo
+end
diff --git a/src/core_lua.c b/src/core_lua.c
index 89e81388a4b9071a2019276f62fcc9c38fc99716..84436712ca0174ecb2590b723aa0a8ed65eb3472 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -820,7 +820,7 @@ static GLenum sdl_gl_texture_format(SDL_Surface *s) {
 
 // allocate memory for a texture without copying pixels in
 // caller binds texture
-static void make_texture_for_surface(SDL_Surface *s) {
+static void make_texture_for_surface(SDL_Surface *s, int *fw, int *fh) {
 	// Paramétrage de la texture.
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
@@ -837,6 +837,8 @@ static void make_texture_for_surface(SDL_Surface *s) {
 	while (realw < s->w) realw *= 2;
 	while (realh < s->h) realh *= 2;
 
+	if (fw) *fw = realw;
+	if (fh) *fh = realh;
 	//printf("request size (%d,%d), producing size (%d,%d)\n",s->w,s->h,realw,realh);
 
 	glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, realw, realh, 0, texture_format, GL_UNSIGNED_BYTE, NULL);
@@ -877,7 +879,7 @@ static int sdl_surface_toscreen(lua_State *L)
 	glGenTextures(1, &t);
 	glBindTexture(GL_TEXTURE_2D, t);
 
-	make_texture_for_surface(*s);
+	make_texture_for_surface(*s, NULL, NULL);
 	copy_surface_to_texture(*s);
 	draw_textured_quad(x,y,(*s)->w,(*s)->h);
 
@@ -913,6 +915,17 @@ static int sdl_surface_toscreen_with_texture(lua_State *L)
 	return 0;
 }
 
+static int sdl_surface_update_texture(lua_State *L)
+{
+	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
+	GLuint *t = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 2);
+
+	glBindTexture(GL_TEXTURE_2D, *t);
+	copy_surface_to_texture(*s);
+
+	return 0;
+}
+
 static int sdl_surface_to_texture(lua_State *L)
 {
 	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
@@ -923,10 +936,14 @@ static int sdl_surface_to_texture(lua_State *L)
 	glGenTextures(1, t);
 	glBindTexture(GL_TEXTURE_2D, *t);
 
-	make_texture_for_surface(*s);
+	int fw, fh;
+	make_texture_for_surface(*s, &fw, &fh);
 	copy_surface_to_texture(*s);
 
-	return 1;
+	lua_pushnumber(L, fw);
+	lua_pushnumber(L, fh);
+
+	return 3;
 }
 
 static int sdl_surface_merge(lua_State *L)
@@ -986,6 +1003,39 @@ static int sdl_texture_toscreen(lua_State *L)
 	return 0;
 }
 
+static int sdl_texture_toscreen_full(lua_State *L)
+{
+	GLuint *t = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 1);
+	int x = luaL_checknumber(L, 2);
+	int y = luaL_checknumber(L, 3);
+	int w = luaL_checknumber(L, 4);
+	int h = luaL_checknumber(L, 5);
+	int rw = luaL_checknumber(L, 6);
+	int rh = luaL_checknumber(L, 7);
+	if (lua_isnumber(L, 8))
+	{
+		float r = luaL_checknumber(L, 9);
+		float g = luaL_checknumber(L, 10);
+		float b = luaL_checknumber(L, 11);
+		float a = luaL_checknumber(L, 12);
+		glColor4f(r, g, b, a);
+	}
+
+	glBindTexture(GL_TEXTURE_2D, *t);
+	GLfloat texw = (GLfloat)w/rw;
+	GLfloat texh = (GLfloat)h/rh;
+
+	glBegin( GL_QUADS );
+	glTexCoord2f(0,0); glVertex2f(0  + x, 0  + y);
+	glTexCoord2f(0,texh); glVertex2f(0  + x, h + y);
+	glTexCoord2f(texw,texh); glVertex2f(w + x, h + y);
+	glTexCoord2f(texw,0); glVertex2f(w + x, 0  + y);
+	glEnd( );
+
+	if (lua_isnumber(L, 8)) glColor4f(1, 1, 1, 1);
+	return 0;
+}
+
 static bool _CheckGL_Error(const char* GLcall, const char* file, const int line)
 {
     GLenum errCode;
@@ -1294,6 +1344,7 @@ static const struct luaL_reg sdl_surface_reg[] =
 	{"merge", sdl_surface_merge},
 	{"toScreen", sdl_surface_toscreen},
 	{"toScreenWithTexture", sdl_surface_toscreen_with_texture},
+	{"updateTexture", sdl_surface_update_texture},
 	{"putChar", lua_display_char},
 	{"drawString", sdl_surface_drawstring},
 	{"drawStringBlended", sdl_surface_drawstring_aa},
@@ -1307,6 +1358,7 @@ static const struct luaL_reg sdl_texture_reg[] =
 	{"__gc", sdl_free_texture},
 	{"close", sdl_free_texture},
 	{"toScreen", sdl_texture_toscreen},
+	{"toScreenFull", sdl_texture_toscreen_full},
 	{"makeOutline", sdl_texture_outline},
 	{"toSurface", gl_texture_to_sdl},
 	{NULL, NULL},