diff --git a/game/engines/default/engine/Map.lua b/game/engines/default/engine/Map.lua
index 5644ea157a128ff1318b1744f0be1dec46d1bed6..57de7f6691c1221e3455ebabaf24cbff320b8faf 100644
--- a/game/engines/default/engine/Map.lua
+++ b/game/engines/default/engine/Map.lua
@@ -722,6 +722,15 @@ function _M:checkMapViewBounded()
 	self._map:setScroll(self.mx, self.my, centered and 0 or self.smooth_scroll)
 end
 
+--- Scrolls the map in the given direction
+function _M:scrollDir(dir)
+	self.changed = true
+	self.mx, self.my = util.coordAddDir(self.mx, self.my, dir)
+	self.mx = util.bound(self.mx, 0, self.w - self.viewport.mwidth)
+	self.my = util.bound(self.my, 0, self.h - self.viewport.mheight)
+	self._map:setScroll(self.mx, self.my, self.smooth_scroll)
+end
+
 --- Gets the tile under the mouse
 function _M:getMouseTile(mx, my)
 --	if mx < self.display_x or my < self.display_y or mx >= self.display_x + self.viewport.width or my >= self.display_y + self.viewport.height then return end
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 0a82529618a4d0224292f4c8e4de9a4915b8522a..ed059d3398891d8627d60cd707c3ad5d4760ace2 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -173,6 +173,13 @@ function _M:run()
 
 	-- Run the current music if any
 	self:onTickEnd(function() self:playMusic() end)
+
+	-- Create the map scroll text overlay
+	self.player_display.font:setStyle("bold")
+	local s = core.display.drawStringBlendedNewSurface(self.player_display.font, "<Scroll mode, press keys to scroll, caps lock to exit>", unpack(colors.simple(colors.GOLD)))
+	self.player_display.font:setStyle("normal")
+	self.caps_scroll = {s:glTexture()}
+	self.caps_scroll.w, self.caps_scroll.h = s:getSize()
 end
 
 --- Checks if the current character is "tainted" by cheating
@@ -913,6 +920,19 @@ function _M:display(nb_keyframes)
 		-- Mouse gestures
 		self.gestures:update()
 		self.gestures:display(map.display_x, map.display_y + map.viewport.height - self.gestures.font_h - 5)
+
+		-- Inform the player that map is in scroll mode
+		if core.key.modState("caps") then
+			local w = map.viewport.width * 0.5
+			local h = w * self.caps_scroll.h / self.caps_scroll.w
+			self.caps_scroll[1]:toScreenFull(
+				map.display_x + (map.viewport.width - w) / 2,
+				map.display_y + (map.viewport.height - h) / 2,
+				w, h,
+				self.caps_scroll[2] * w / self.caps_scroll.w, self.caps_scroll[3] * h / self.caps_scroll.h,
+				1, 1, 1, 0.5
+			)
+		end
 	end
 
 	-- We display the player's interface
@@ -1033,15 +1053,15 @@ function _M:setupCommands()
 	self.key:addBinds
 	{
 		-- Movements
-		MOVE_LEFT = function() self.player:moveDir(4) end,
-		MOVE_RIGHT = function() self.player:moveDir(6) end,
-		MOVE_UP = function() self.player:moveDir(8) end,
-		MOVE_DOWN = function() self.player:moveDir(2) end,
-		MOVE_LEFT_UP = function() self.player:moveDir(7) end,
-		MOVE_LEFT_DOWN = function() self.player:moveDir(1) end,
-		MOVE_RIGHT_UP = function() self.player:moveDir(9) end,
-		MOVE_RIGHT_DOWN = function() self.player:moveDir(3) end,
-		MOVE_STAY = function() if self.player:enoughEnergy() then self.player:describeFloor(self.player.x, self.player.y) self.player:useEnergy() end end,
+		MOVE_LEFT = function() if core.key.modState("caps") and self.level then self.level.map:scrollDir(4) else self.player:moveDir(4) end end,
+		MOVE_RIGHT = function() if core.key.modState("caps") and self.level then self.level.map:scrollDir(6) else self.player:moveDir(6) end end,
+		MOVE_UP = function() if core.key.modState("caps") and self.level then self.level.map:scrollDir(8) else self.player:moveDir(8) end end,
+		MOVE_DOWN = function() if core.key.modState("caps") and self.level then self.level.map:scrollDir(2) else self.player:moveDir(2) end end,
+		MOVE_LEFT_UP = function() if core.key.modState("caps") and self.level then self.level.map:scrollDir(7) else self.player:moveDir(7) end end,
+		MOVE_LEFT_DOWN = function() if core.key.modState("caps") and self.level then self.level.map:scrollDir(1) else self.player:moveDir(1) end end,
+		MOVE_RIGHT_UP = function() if core.key.modState("caps") and self.level then self.level.map:scrollDir(9) else self.player:moveDir(9) end end,
+		MOVE_RIGHT_DOWN = function() if core.key.modState("caps") and self.level then self.level.map:scrollDir(3) else self.player:moveDir(3) end end,
+		MOVE_STAY = function() if core.key.modState("caps") and self.level then self.level.map:centerViewAround(self.player.x, self.player.y) else if self.player:enoughEnergy() then self.player:describeFloor(self.player.x, self.player.y) self.player:useEnergy() end end end,
 
 		RUN = function()
 			game.log("Run in which direction?")
diff --git a/game/modules/tome/data/lore/shertul.lua b/game/modules/tome/data/lore/shertul.lua
index d34c3d14b1c45fb91cd79ab1313c65e0a1cbef0a..ff5be551874b0409c3f59f579c6b6657877003ee 100644
--- a/game/modules/tome/data/lore/shertul.lua
+++ b/game/modules/tome/data/lore/shertul.lua
@@ -108,3 +108,11 @@ newLore{
 	image = "shertul_fortress_lore9.png",
 	lore = function() return [[This final mural has been ruined, with deep scores and scratches etched across its surface. All you can see of the original appears to be flames.]] end,
 }
+
+newLore{
+	id = "shertul-fortress-takeoff",
+	category = "sher'tul",
+	name = "Yiilkgur raising toward the sky",
+	image = "fortress_takeoff.png",
+	lore = [[Yiilkgur, the Sher'Tul Fortress is re-activated and raises from the depths of Nur toward the sky.]],
+}
diff --git a/game/modules/tome/data/quests/shertul-fortress.lua b/game/modules/tome/data/quests/shertul-fortress.lua
index 64126f1b6c047b7f6e0a1fe084938b81e90bfea2..cd4335f742933a7f0d1194603460cb8f5f38953d 100644
--- a/game/modules/tome/data/quests/shertul-fortress.lua
+++ b/game/modules/tome/data/quests/shertul-fortress.lua
@@ -151,6 +151,8 @@ upgrade_rod = function(self)
 end
 
 fly = function(self)
+	game.player:learnLore("shertul-fortress-takeoff")
+
 	local f = require("mod.class.FortressPC").new{}
 	game:changeLevel(1, "wilderness")
 	game.party:addMember(f, {temporary_level=1, control="full"})
diff --git a/game/modules/tome/dialogs/ShowLore.lua b/game/modules/tome/dialogs/ShowLore.lua
index 39d1a79e15b9c878470abe6c3038d6576ce7afc7..a81b4af106797e4b0199ffb6b19de55bc8580cc5 100644
--- a/game/modules/tome/dialogs/ShowLore.lua
+++ b/game/modules/tome/dialogs/ShowLore.lua
@@ -28,6 +28,7 @@ module(..., package.seeall, class.inherit(Dialog))
 
 function _M:init(title, actor)
 	self.actor = actor
+	print("Lore of player", actor.name)
 	local total = #actor.lore_defs + actor.additional_lore_nb
 	local nb = 0
 	for id, data in pairs(actor.lore_known) do nb = nb + 1 end
diff --git a/src/core_lua.c b/src/core_lua.c
index 5be7572f556484ecc2ac4ddda397703107e774e9..4a82d7a20a1a636afdf921b6ffd3663901e25e4f 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -184,6 +184,7 @@ static int lua_get_mod_state(lua_State *L)
 	else if (!strcmp(mod, "ctrl")) lua_pushboolean(L, smod & KMOD_CTRL);
 	else if (!strcmp(mod, "alt")) lua_pushboolean(L, smod & KMOD_ALT);
 	else if (!strcmp(mod, "meta")) lua_pushboolean(L, smod & KMOD_META);
+	else if (!strcmp(mod, "caps")) lua_pushboolean(L, smod & KMOD_CAPS);
 	else lua_pushnil(L);
 
 	return 1;