diff --git a/game/engine/Quest.lua b/game/engine/Quest.lua
index e05e859559e6bd554ec1a5a5ed25e97592bd9559..7e8f431fb0615ecc2fa5a093170f7cedde337950 100644
--- a/game/engine/Quest.lua
+++ b/game/engine/Quest.lua
@@ -43,11 +43,11 @@ function _M:check(prop, ...)
 	end
 end
 
---- Sets the quets status or sub-objective status
+--- Sets the quests status or sub-objective status
 -- @param status one of the possible quest status (PENDING, COMPLETED, DONE, FAILED)
 function _M:setStatus(status, sub, who)
 	if sub then
-		if self.objectives[sub] == status then return false end
+		if self.objectives[sub] and self.objectives[sub] == status then return false end
 		self.objectives[sub] = status
 		self:check("on_status_change", who, status, sub)
 		return true
@@ -58,3 +58,15 @@ function _M:setStatus(status, sub, who)
 		return true
 	end
 end
+
+--- Checks the quests status or sub-objective status
+-- @param status one of the possible quest status (PENDING, COMPLETED, DONE, FAILED)
+function _M:isStatus(status, sub)
+	if sub then
+		if self.objectives[sub] and self.objectives[sub] == status then return true end
+		return false
+	else
+		if self.status == status then return true end
+		return false
+	end
+end
diff --git a/game/engine/interface/ActorInventory.lua b/game/engine/interface/ActorInventory.lua
index 53cc8d83ba85b227c28cfa3517ace29428e8d05d..920d5018735d5127be32c3126642ca721b009a1d 100644
--- a/game/engine/interface/ActorInventory.lua
+++ b/game/engine/interface/ActorInventory.lua
@@ -68,6 +68,8 @@ function _M:addObject(inven_id, o)
 	-- No room ?
 	if #inven >= inven.max then return false end
 
+	if o:check("on_preaddobject", self, inven) then return false end
+
 	-- Ok add it
 	table.insert(inven, o)
 
@@ -111,7 +113,11 @@ end
 -- @return the object removed or nil if no item existed
 function _M:removeObject(inven, item, no_unstack)
 	if type(inven) == "number" then inven = self.inven[inven] end
+
 	local o, finish = inven[item], true
+
+	if o:check("on_preremoveobject", self, inven) then return false end
+
 	if not no_unstack then
 		o, finish = o:unstack()
 	end
@@ -139,14 +145,16 @@ end
 -- @param item the item id to drop
 -- @return the object removed or nil if no item existed
 function _M:dropFloor(inven, item, vocal, all)
-	local o = self:removeObject(inven, item, all)
+	local o = self:getInven(inven)[item]
 	if not o then
 		if vocal then game.logSeen(self, "There is nothing to drop.") end
 		return
 	end
-	if o:check("on_drop", self) then return end
+	if o:check("on_drop", self) then return false end
+	o = self:removeObject(inven, item, all)
 	game.level.map:addObject(self.x, self.y, o)
 	if vocal then game.logSeen(self, "%s drops on the floor: %s.", self.name:capitalize(), o:getName{do_color=true}) end
+	return true
 end
 
 --- Show inventory dialog
@@ -231,6 +239,7 @@ function _M:wearObject(o, replace, vocal)
 		if vocal then game.logSeen(self, "%s can not wear: %s (%s).", self.name:capitalize(), o:getName{do_color=true}, err) end
 		return false
 	end
+	if o:check("on_canwear", self, inven) then return false end
 
 	if self:addObject(inven, o) then
 		if vocal then game.logSeen(self, "%s wears: %s.", self.name:capitalize(), o:getName{do_color=true}) end
@@ -258,7 +267,10 @@ end
 
 --- Takeoff item
 function _M:takeoffObject(inven, item)
-	local o = self:removeObject(inven, item, true)
+	local o = self:getInven(inven)[item]
+	if o:check("on_cantakeoff", self, inven) then return false end
+
+	o = self:removeObject(inven, item, true)
 	return o
 end
 
@@ -317,8 +329,22 @@ function _M:sortInven(inven)
 end
 
 --- Finds an object by name in an inventory
-function _M:findInInventory(inven, name)
+-- @param inven the inventory to look into
+-- @param name the name to look for
+-- @param getname the parameters to pass to getName(), if nil the default is {no_count=true, force_id=true}
+function _M:findInInventory(inven, name, getname)
+	getname = getname or {no_count=true, force_id=true}
 	for item, o in ipairs(inven) do
-		if o:getName{no_count=true} == name then return o, item end
+		if o:getName(getname) == name then return o, item end
+	end
+end
+
+--- Finds an object by name in all the actor's inventories
+-- @param name the name to look for
+-- @param getname the parameters to pass to getName(), if nil the default is {no_count=true, force_id=true}
+function _M:findInAllInventories(name, getname)
+	for inven_id, inven in pairs(self.inven) do
+		local o, item = self:findInInventory(inven, name, getname)
+		if o and item then return o, item, inven_id end
 	end
 end
diff --git a/game/engine/interface/ActorQuest.lua b/game/engine/interface/ActorQuest.lua
index 27fb2dc031d7daf12369bc56128988ce848b3358..3e65ba41585cab3a18e0d19b43ab3c4172c39302 100644
--- a/game/engine/interface/ActorQuest.lua
+++ b/game/engine/interface/ActorQuest.lua
@@ -45,3 +45,12 @@ function _M:hasQuest(id)
 	if not self.quests then return false end
 	return self.quests[id] and true or false
 end
+
+--- Checks the status of the given quest
+-- If the actor does not have the quest, does nothing
+function _M:isQuestStatus(quest, status, sub)
+	if not self.quests then return end
+	local q = self.quests[quest]
+	if not q then return end
+	return q:isStatus(status, sub)
+end
diff --git a/game/modules/tome/data/chats/minas-tirith-elder.lua b/game/modules/tome/data/chats/minas-tirith-elder.lua
index 31c78b4a431e05ab025356af27f233d0ef6e53a4..988aaa66b2c2aa9e3ba3e169bdede4f7a067ace6 100644
--- a/game/modules/tome/data/chats/minas-tirith-elder.lua
+++ b/game/modules/tome/data/chats/minas-tirith-elder.lua
@@ -2,7 +2,7 @@ newChat{ id="welcome",
 	text = [[Welcome @playername@ to Minas Tirith traveler, please be quick my time is precious.]],
 	answers = {
 		{"Nothing, excuse me. Bye!"},
-		{"I have found this staff in my travels, it looks really old and powerful. I dare not use it.", jump="found_staff"},
+		{"I have found this staff in my travels, it looks really old and powerful. I dare not use it.", jump="found_staff", cond=function(npc, player) return player:isQuestStatus("staff-absorption", engine.Quest.PENDING) and player:findInAllInventories("Staff of Absorption") end},
 	}
 }
 
@@ -12,6 +12,10 @@ Please surrender the staff to the protection of the King while we work to learn
 This could be related to the rumours we hear from the far east...]],
 	answers = {
 		{"Take it Sir.", action=function(npc, player)
+			local o, item, inven_id = player:findInAllInventories("Staff of Absorption")
+			player:removeObject(inven_id, item, true)
+			o:removed()
+
 			player:setQuestStatus("staff-absorption", engine.Quest.DONE)
 			player.winner = true
 			local D = require "engine.Dialog"
diff --git a/game/modules/tome/data/general/objects/quest-artifacts.lua b/game/modules/tome/data/general/objects/quest-artifacts.lua
index 4158a938782bc636e6d27e2672c56a608d5fb145..93f4feda02f8db1c714bdbdc2e70b84d68ae802a 100644
--- a/game/modules/tome/data/general/objects/quest-artifacts.lua
+++ b/game/modules/tome/data/general/objects/quest-artifacts.lua
@@ -36,4 +36,10 @@ newEntity{ define_as = "STAFF_ABSORPTION",
 			who:grantQuest("staff-absorption")
 		end
 	end,
+	on_drop = function(self, who)
+		if who == game.player then
+			game.logPlayer(who, "You cannot bring yourself to drop the %s", self:getName())
+			return true
+		end
+	end,
 }