diff --git a/game/engines/default/data/keybinds/actions.lua b/game/engines/default/data/keybinds/actions.lua
index 5f43ef94cec30eb77d536a2dd5cfc1eced4609f4..bba236c11d5397c104a4704e8a877cb48837f501 100644
--- a/game/engines/default/data/keybinds/actions.lua
+++ b/game/engines/default/data/keybinds/actions.lua
@@ -94,7 +94,7 @@ defineAction{
 }
 
 defineAction{
-	default = { "uni:C" },
+	default = { "uni:c", "uni:C" },
 	type = "SHOW_CHARACTER_SHEET",
 	group = "actions",
 	name = "Show character sheet",
diff --git a/game/engines/default/engine/HotkeysDisplay.lua b/game/engines/default/engine/HotkeysDisplay.lua
index 4aa713b32f76189c807fc557b57d2420d59ea76d..5e0b24794044cbe966cb8989010fad982f9ff9c9 100644
--- a/game/engines/default/engine/HotkeysDisplay.lua
+++ b/game/engines/default/engine/HotkeysDisplay.lua
@@ -50,10 +50,6 @@ function _M:resize(x, y, w, h)
 	self.texture, self.texture_w, self.texture_h = self.surface:glTexture()
 	if self.actor then self.actor.changed = true end
 
-	local cw, ch = self.font:size(" ")
-	self.font_w = cw
-	self.max_char_w = math.min(127, math.floor(w / self.font_w))
-
 	if self.bg_image then
 		local fill = core.display.loadImage(self.bg_image)
 		local fw, fh = fill:getSize()
@@ -73,14 +69,17 @@ function _M:display()
 	local a = self.actor
 	if not a or not a.changed then return self.surface end
 
+	local page = a.hotkey_page
+	if page == 1 and core.key.modState("ctrl") then page = 2
+	elseif page == 1 and core.key.modState("shift") then page = 3 end
+
 	local hks = {}
 	for i = 1, 12 do
-		local j = i + (12 * (a.hotkey_page - 1))
-		local ks = game.key:formatKeyString(game.key:findBoundKeys("HOTKEY_"..page_to_hotkey[a.hotkey_page]..i))
+		local j = i + (12 * (page - 1))
 		if a.hotkey[j] and a.hotkey[j][1] == "talent" then
-			hks[#hks+1] = {a.hotkey[j][2], j, "talent", ks}
+			hks[#hks+1] = {a.hotkey[j][2], i, "talent"}
 		elseif a.hotkey[j] and a.hotkey[j][1] == "inventory" then
-			hks[#hks+1] = {a.hotkey[j][2], j, "inventory", ks}
+			hks[#hks+1] = {a.hotkey[j][2], i, "inventory"}
 		end
 	end
 
@@ -122,14 +121,14 @@ function _M:display()
 			end
 		end
 
-		txt = ("%1d/%2d) %-"..(self.max_char_w-4-24).."s Key: %s"):format(a.hotkey_page, i - (a.hotkey_page-1) * 12, txt, ts[4])
+		txt = ("%1d/%2d) %s"):format(page, i, txt)
 		local w, h, gen
 		if self.cache[txt] then
 			gen = self.cache[txt]
 			w, h = gen.fw, gen.fh
 		else
 			w, h = self.font:size(txt)
-			gen = self.font:draw(txt, self.w, color[1], color[2], color[3], true)[1]
+			gen = self.font:draw(txt, self.w / 3, color[1], color[2], color[3], true)[1]
 			gen.fw, gen.fh = w, h
 		end
 		gen.x, gen.y = x, y
@@ -138,7 +137,7 @@ function _M:display()
 		self.clics[i] = {x,y,w+4,h+4}
 
 		if y + self.font_h * 2 > self.h then
-			x = x + self.w / 2
+			x = x + self.w / 3
 			y = 0
 		else
 			y = y + self.font_h
diff --git a/game/engines/default/engine/LogDisplay.lua b/game/engines/default/engine/LogDisplay.lua
index 6b6e3b50bc35a074b1d6e1b8f1067b307fa08cb2..83c31877a0d62ead956502018a3d2f03d7ded2c1 100644
--- a/game/engines/default/engine/LogDisplay.lua
+++ b/game/engines/default/engine/LogDisplay.lua
@@ -50,6 +50,10 @@ function _M:enableShadow(v)
 	self.shadow = v
 end
 
+function _M:enableFading(v)
+	self.fading = v
+end
+
 --- Resize the display area
 function _M:resize(x, y, w, h)
 	self.display_x, self.display_y = math.floor(x), math.floor(y)
@@ -72,9 +76,22 @@ function _M:resize(x, y, w, h)
 	self.scrollbar = Slider.new{size=self.h - 20, max=1, inverse=true}
 end
 
+--- Returns the full log
+function _M:getLog()
+	local log = {}
+	for i = 1, #self.log do log[#log+1] = self.log[i].str end
+	return log
+end
+
+function _M:getLogLast(channel)
+	if not self.log[1] then return 0 end
+	return self.log[1].timestamp
+end
+
 --- Make a dialog popup with the full log
 function _M:showLogDialog(title, shadow)
-	local d = require("engine.dialogs.ShowLog").new(title or "Message Log", shadow, self)
+	local log = self:getLog()
+	local d = require_first("mod.dialogs.ShowLog", "engine.dialogs.ShowLog").new(title or "Message Log", shadow, {log=log})
 	game:registerDialog(d)
 end
 
@@ -86,7 +103,7 @@ function _M:call(str, ...)
 	str = str:format(...)
 	print("[LOG]", str)
 	local tstr = str:toString()
-	table.insert(self.log, 1, tstr)
+	table.insert(self.log, 1, {str=tstr, timestamp = core.game.getTime()})
 	while #self.log > self.max_log do
 		local old = table.remove(self.log)
 		self.cache[old] = nil
@@ -109,7 +126,7 @@ function _M:getLines(number)
 	if from > #self.log then from = #self.log end
 	local lines = { }
 	for i = from, 1, -1 do
-		lines[#lines+1] = tostring(self.log[i])
+		lines[#lines+1] = tostring(self.log[i].str)
 	end
 	return lines
 end
@@ -125,7 +142,7 @@ function _M:display()
 	local old_style = self.font:getStyle()
 	for z = 1 + self.scroll, #self.log do
 		local stop = false
-		local tstr = self.log[z]
+		local tstr = self.log[z].str
 		local gen
 		if self.cache[tstr] then
 			gen = self.cache[tstr]
@@ -134,7 +151,7 @@ function _M:display()
 			self.cache[tstr] = gen
 		end
 		for i = #gen, 1, -1 do
-			self.dlist[#self.dlist+1] = gen[i]
+			self.dlist[#self.dlist+1] = {item=gen[i], date=self.log[z].timestamp}
 			h = h + self.fh
 			if h > self.h - self.fh then stop=true break end
 		end
@@ -146,16 +163,29 @@ end
 
 function _M:toScreen()
 	self:display()
+
 	if self.bg_texture then self.bg_texture:toScreenFull(self.display_x, self.display_y, self.w, self.h, self.bg_texture_w, self.bg_texture_h) end
+
+	local now = core.game.getTime()
+
 	local h = self.display_y + self.h -  self.fh
 	for i = 1, #self.dlist do
-		local item = self.dlist[i]
-		if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, self.fw, self.fh, item._tex_w, item._tex_h, 0,0,0, self.shadow) end
-		item._tex:toScreenFull(self.display_x, h, self.fw, self.fh, item._tex_w, item._tex_h)
+		local item = self.dlist[i].item
+
+		local fade = 1
+		if self.fading then
+			fade = now - self.dlist[i].date
+			if fade < self.fading * 1000 then fade = 1
+			elseif fade < self.fading * 2000 then fade = (self.fading * 2000 - fade) / (self.fading * 1000)
+			else fade = 0 end
+		end
+
+		if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, self.fw, self.fh, item._tex_w, item._tex_h, 0,0,0, self.shadow * fade) end
+		item._tex:toScreenFull(self.display_x, h, self.fw, self.fh, item._tex_w, item._tex_h, 1, 1, 1, fade)
 		h = h - self.fh
 	end
 
-	if true then
+	if not self.fading then
 		self.scrollbar.pos = self.scroll
 		self.scrollbar.max = self.max - self.max_display + 1
 		self.scrollbar:display(self.display_x + self.w - self.scrollbar.w, self.display_y)
diff --git a/game/engines/default/engine/Map.lua b/game/engines/default/engine/Map.lua
index 7d74de5e6fa0d475bd616f3f764aedf1eca36d5b..6c5cea8443b1a9d609bc5cf3cf21ecfef7f7393f 100644
--- a/game/engines/default/engine/Map.lua
+++ b/game/engines/default/engine/Map.lua
@@ -182,6 +182,7 @@ function _M:save()
 		_map = true,
 		_fovcache = true,
 		surface = true,
+		finished = true,
 	})
 end
 
@@ -287,6 +288,7 @@ end
 
 --- Recreate the internal map using new dimensions
 function _M:recreate()
+	if not self.finished then return end
 	self:makeCMap()
 	self.changed = true
 
diff --git a/game/engines/default/engine/UserChat.lua b/game/engines/default/engine/UserChat.lua
index f16d257729b97a6ad2b75e49d6ca35d6c7d44eac..e2251515dc7bb0fdd76b71d493492cc329a4789e 100644
--- a/game/engines/default/engine/UserChat.lua
+++ b/game/engines/default/engine/UserChat.lua
@@ -34,6 +34,7 @@ function _M:init()
 	self.cur_channel = "global"
 	self.channels = {}
 	self.max = 500
+	self.do_display_chans = true
 end
 
 --- Hook up in the current running game
@@ -63,7 +64,7 @@ end
 
 function _M:addMessage(channel, login, name, msg, extra_data, no_change)
 	local log = self.channels[channel].log
-	table.insert(log, 1, {login=login, name=name, msg=msg, extra_data=extra_data})
+	table.insert(log, 1, {login=login, name=name, msg=msg, extra_data=extra_data, timestamp=core.game.getTime()})
 	while #log > self.max do table.remove(log) end
 	self.changed = true
 	if not no_change and channel ~= self.cur_channel then self.channels[channel].changed = true self.channels_changed = true end
@@ -254,15 +255,32 @@ end
 -- UI Section
 ----------------------------------------------------------------
 
---- Make a dialog popup with the full log
-function _M:showLogDialog(title, shadow)
+--- Returns the full log
+function _M:getLog(channel)
+	channel = channel or self.cur_channel
 	local log = {}
-	if self.channels[self.cur_channel] then
-		for _, i in ipairs(self.channels[self.cur_channel].log) do
+	if self.channels[channel] then
+		for _, i in ipairs(self.channels[channel].log) do
 			log[#log+1] = ("<%s> %s"):format(i.name, i.msg)
 		end
 	end
-	local d = require("engine.dialogs.ShowLog").new(title or "Chat Log", shadow, {log=log})
+	return log
+end
+
+function _M:getLogLast(channel)
+	channel = channel or self.cur_channel
+	if self.channels[channel] then
+		if not self.channels[channel].log[1] then return 0 end
+		return self.channels[channel].log[1].timestamp
+	else
+		return 0
+	end
+end
+
+--- Make a dialog popup with the full log
+function _M:showLogDialog(title, shadow)
+	local log = self:getLog(self.cur_channel)
+	local d = require_first("mod.dialogs.ShowLog", "engine.dialogs.ShowLog").new(title or "Chat Log", shadow, {log=log})
 	game:registerDialog(d)
 end
 
@@ -342,6 +360,14 @@ function _M:enableShadow(v)
 	self.shadow = v
 end
 
+function _M:enableFading(v)
+	self.fading = v
+end
+
+function _M:enableDisplayChans(v)
+	self.do_display_chans = v
+end
+
 function _M:onMouse(fct)
 	self.on_mouse = fct
 end
@@ -386,9 +412,9 @@ function _M:display()
 		for i = #gen, 1, -1 do
 			gen[i].login = log[z].login
 			gen[i].extra_data = log[z].extra_data
-			self.dlist[#self.dlist+1] = gen[i]
+			self.dlist[#self.dlist+1] = {item=gen[i], date=log[z].timestamp}
 			h = h + self.fh
-			if h > self.h - self.fh - self.fh then stop=true break end
+			if h > self.h - self.fh - (self.do_display_chans and self.fh or 0) then stop=true break end
 		end
 		if stop then break end
 	end
@@ -400,30 +426,42 @@ function _M:toScreen()
 	self:display()
 	if self.bg_texture then self.bg_texture:toScreenFull(self.display_x, self.display_y, self.w, self.h, self.bg_texture_w, self.bg_texture_h) end
 	local h = self.display_y + self.h -  self.fh
+	local now = core.game.getTime()
 	for i = 1, #self.dlist do
-		local item = self.dlist[i]
+		local item = self.dlist[i].item
+
+		local fade = 1
+		if self.fading then
+			fade = now - self.dlist[i].date
+			if fade < self.fading * 1000 then fade = 1
+			elseif fade < self.fading * 2000 then fade = (self.fading * 2000 - fade) / (self.fading * 1000)
+			else fade = 0 end
+		end
+
 		item.dh = h
-		if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow) end
-		item._tex:toScreenFull(self.display_x, h, item.w, item.h, item._tex_w, item._tex_h)
+		if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow * fade) end
+		item._tex:toScreenFull(self.display_x, h, item.w, item.h, item._tex_w, item._tex_h, 1, 1, 1, fade)
 		h = h - self.fh
 	end
 
-	local w = 0
-	for i = 1, #self.display_chans do
-		local item = self.display_chans[i]
-		local f = item.sel and self.frame_sel or self.frame
-		f.w = item.w
-
-		Base:drawFrame(f, self.display_x + w, self.display_y)
-		if self.channels[item.name].changed then
-			local glow = (1+math.sin(core.game.getTime() / 500)) / 2 * 100 + 120
-			Base:drawFrame(f, self.display_x + w, self.display_y, 139/255, 210/255, 77/255, glow / 255)
+	if self.do_display_chans then
+		local w = 0
+		for i = 1, #self.display_chans do
+			local item = self.display_chans[i]
+			local f = item.sel and self.frame_sel or self.frame
+			f.w = item.w
+
+			Base:drawFrame(f, self.display_x + w, self.display_y)
+			if self.channels[item.name].changed then
+				local glow = (1+math.sin(core.game.getTime() / 500)) / 2 * 100 + 120
+				Base:drawFrame(f, self.display_x + w, self.display_y, 139/255, 210/255, 77/255, glow / 255)
+			end
+			item._tex:toScreenFull(self.display_x + w, self.display_y, item.w, item.h, item._tex_w, item._tex_h)
+			w = w + item.w + 4
 		end
-		item._tex:toScreenFull(self.display_x + w, self.display_y, item.w, item.h, item._tex_w, item._tex_h)
-		w = w + item.w + 4
 	end
 
-	if true then
+	if not self.fading then
 		self.scrollbar.pos = self.scroll
 		self.scrollbar.max = self.max - self.max_display + 1
 		self.scrollbar:display(self.display_x + self.w - self.scrollbar.w, self.display_y)
diff --git a/game/engines/default/engine/interface/GameTargeting.lua b/game/engines/default/engine/interface/GameTargeting.lua
index b9661a75ae65853bd0736817d74cddf17e070b86..8748664d1d43af2ca6a214d92de72d2ffe2c2b35 100644
--- a/game/engines/default/engine/interface/GameTargeting.lua
+++ b/game/engines/default/engine/interface/GameTargeting.lua
@@ -195,6 +195,8 @@ end
 --- Handle mouse event for targeting
 -- @return true if the event was handled
 function _M:targetMouse(button, mx, my, xrel, yrel, event)
+	if not self.level then return end
+
 	-- Move tooltip
 	self.tooltip_x, self.tooltip_y = mx, my
 	local tmx, tmy = self.level.map:getMouseTile(mx, my)
diff --git a/game/engines/default/engine/interface/PlayerMouse.lua b/game/engines/default/engine/interface/PlayerMouse.lua
index 75d906890f8b89371a828039c3a81f0124f39388..426519d9abac4a502e5f152a2a0d0165ecc936a1 100644
--- a/game/engines/default/engine/interface/PlayerMouse.lua
+++ b/game/engines/default/engine/interface/PlayerMouse.lua
@@ -120,6 +120,7 @@ end
 -- @param key the Key object to which to pass the event if not treated, this should be your game default key handler probably
 -- @param allow_move true if this will allow player movement (you should use it to check that you are not in targetting mode)
 function _M:mouseHandleDefault(key, allow_move, button, mx, my, xrel, yrel, event)
+	if not game.level then return end
 	local tmx, tmy = game.level.map:getMouseTile(mx, my)
 
 	-- Move
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 5e232ccf6e65e1a3ee1c113ffc185f67492cd1a7..f5173515355fc829c29caef1151477d9db433c77 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -81,7 +81,7 @@ function _M:init()
 end
 
 function _M:run()
-	local size, size_mono, font, font_mono
+	local size, size_mono, font, font_mono, font_mono_h, font_h
 	local flysize = ({normal=14, small=12, big=16})[config.settings.tome.fonts.size]
 	if config.settings.tome.fonts.type == "fantasy" then
 		size = ({normal=16, small=14, big=18})[config.settings.tome.fonts.size]
@@ -94,16 +94,27 @@ function _M:run()
 		font = "/data/font/Vera.ttf"
 		font_mono = "/data/font/VeraMono.ttf"
 	end
+	local f = core.display.newFont(font, size)
+	font_h = f:lineSkip()
+	f = core.display.newFont(font_mono, size_mono)
+	font_mono_h = f:lineSkip()
 
 	self.delayed_log_damage = {}
 	self.calendar = Calendar.new("/data/calendar_allied.lua", "Today is the %s %s of the %s year of the Age of Ascendancy of Maj'Eyal.\nThe time is %02d:%02d.", 122, 167, 11)
 
-	self.player_display = PlayerDisplay.new(0, 230, 200, self.h * 0.8 - 230, {30,30,0}, font_mono, size_mono)
-	self.flash = LogFlasher.new(0, 0, self.w, 20, nil, font, size, {255,255,255}, {0,0,0})
-	self.logdisplay = LogDisplay.new(0, self.h * 0.8 + 7, self.w * 0.5 - 46, self.h * 0.2 - 7, nil, font, size, {255,255,255}, "/data/gfx/ui/message-log.png")
+	self.player_display = PlayerDisplay.new(0, 200, 200, self.h - 200, {30,30,0}, font_mono, size_mono)
+--	self.flash = LogFlasher.new(0, 0, self.w, 20, nil, font, size, {255,255,255}, {0,0,0})
+	self.map_h_stop = self.h - font_mono_h * 4
+	self.logdisplay = LogDisplay.new(216, self.map_h_stop - font_h * 5 -16, (self.w - 216) / 2, font_h * 5, nil, font, size, nil, nil)
 	self.logdisplay:enableShadow(0.6)
-	profile.chat:resize(0, self.h * 0.8 + 7, self.w * 0.5 - 46, self.h * 0.2 - 7, font, size, {255,255,255}, "/data/gfx/ui/message-log.png")
-	self.hotkeys_display = HotkeysDisplay.new(nil, self.w * 0.5 + 46, self.h * 0.8 + 7, self.w * 0.5 - 46, self.h * 0.2 - 7, "/data/gfx/ui/talents-list.png", font_mono, size_mono)
+	self.logdisplay:enableFading(2)
+
+	profile.chat:resize(216 + (self.w - 216) / 2, self.map_h_stop - font_h * 5 -16, (self.w - 216) / 2, font_h * 5, font, size, nil, nil)
+	profile.chat:enableShadow(0.6)
+	profile.chat:enableFading(6)
+	profile.chat:enableDisplayChans(false)
+
+	self.hotkeys_display = HotkeysDisplay.new(nil, 216, self.h - font_mono_h * 4, self.w - 216, font_mono_h * 4, "/data/gfx/ui/talents-list.png", font_mono, size_mono)
 	self.hotkeys_display:enableShadow(0.6)
 	self.npcs_display = ActorsSeenDisplay.new(nil, self.w * 0.5 + 46, self.h * 0.8 + 7, self.w * 0.5 - 46, self.h * 0.2 - 7, "/data/gfx/ui/talents-list.png", font_mono, size_mono)
 	self.tooltip = Tooltip.new(font_mono, size, {255,255,255}, {30,30,30,230})
@@ -116,34 +127,22 @@ function _M:run()
 	self.nicer_tiles = NicerTiles.new()
 	self:createSeparators()
 
-	self.log = function(style, ...) if type(style) == "number" then self.logdisplay(...) self.flash(style, ...) else self.logdisplay(style, ...) self.flash(self.flash.NEUTRAL, style, ...) end end
+	self.log = function(style, ...) if type(style) == "number" then self.logdisplay(...) else self.logdisplay(style, ...) end end
 	self.logChat = function(style, ...)
-		if not config.settings.tome.chat_log then return end
+		if true or not config.settings.tome.chat_log then return end
 		if type(style) == "number" then
 		local old = self.logdisplay.changed
-		self.logdisplay(...) self.flash(style, ...) else self.logdisplay(style, ...) self.flash(self.flash.NEUTRAL, style, ...) end
+		self.logdisplay(...) else self.logdisplay(style, ...) end
 		if self.show_userchat then self.logdisplay.changed = old end
 	end
 	self.logSeen = function(e, style, ...) if e and e.x and e.y and self.level.map.seens(e.x, e.y) then self.log(style, ...) end end
 	self.logPlayer = function(e, style, ...) if e == self.player or e == self.party then self.log(style, ...) end end
 
-	self.log(self.flash.GOOD, "Welcome to #00FF00#Tales of Maj'Eyal!")
+--	self.log(self.flash.GOOD, "Welcome to #00FF00#Tales of Maj'Eyal!")
 
 	-- List of stuff to do on tick end
 	self.on_tick_end = {}
 
-	-- Setup inputs
-	self:setupCommands()
-	self:setupMouse()
-
-	-- Starting from here we create a new game
-	if not self.player then self:newGame() end
-
-	self.hotkeys_display.actor = self.player
-	self.npcs_display.actor = self.player
-
-	self:initTargeting()
-
 	-- Ok everything is good to go, activate the game in the engine!
 	self:setCurrent()
 
@@ -153,9 +152,21 @@ function _M:run()
 	-- Start time
 	self.real_starttime = os.time()
 
-	if self.level then self:setupDisplayMode(false, "postinit") end
+	self:setupDisplayMode(false, "postinit")
 	if self.level and self.level.data.day_night then self.state:dayNightCycle() end
 	if self.level and self.player then self.calendar = Calendar.new("/data/calendar_"..(self.player.calendar or "allied")..".lua", "Today is the %s %s of the %s year of the Age of Ascendancy of Maj'Eyal.\nThe time is %02d:%02d.", 122, 167, 11) end
+
+	-- Setup inputs
+	self:setupCommands()
+	self:setupMouse()
+
+	-- Starting from here we create a new game
+	if not self.player then self:newGame() end
+
+	self:initTargeting()
+
+	self.hotkeys_display.actor = self.player
+	self.npcs_display.actor = self.player
 end
 
 --- Checks if the current character is "tainted" by cheating
@@ -315,6 +326,7 @@ function _M:loaded()
 	Zone.post_filter = function(...) return self.state:entityFilterPost(...) end
 	Map:setViewerActor(self.player)
 	self:setupDisplayMode(false, "init")
+	self:setupDisplayMode(false, "postinit")
 	if self.player then self.player.changed = true end
 	self.key = engine.KeyBind.new()
 
@@ -334,6 +346,14 @@ function _M:setupDisplayMode(reboot, mode)
 			util.showMainMenu(false, nil, nil, self.__mod_info.short_name, self.save_name, false)
 		end
 
+		local do_bg = true
+
+		Map:resetTiles()
+	end
+
+	if not mode or mode == "postinit" then
+		local gfx = config.settings.tome.gfx
+
 		-- Show a count for stacked objects
 		Map.object_stack_count = true
 
@@ -345,20 +365,14 @@ function _M:setupDisplayMode(reboot, mode)
 		print("[DISPLAY MODE] Tileset: "..gfx.tiles)
 		print("[DISPLAY MODE] Size: "..gfx.size)
 
-		local do_bg = true
-
 		if gfx.size == "64x64" then
-			Map:setViewPort(216, 36, self.w - 216, math.floor(self.h * 0.80) - 36, 64, 64, nil, 44, do_bg)
-			Map:resetTiles()
+			Map:setViewPort(216, 0, self.w - 216, (self.map_h_stop or 80) - 16, 64, 64, nil, 44, do_bg)
 		elseif gfx.size == "48x48" then
-			Map:setViewPort(216, 36, self.w - 216, math.floor(self.h * 0.80) - 36, 48, 48, nil, 36, do_bg)
-			Map:resetTiles()
+			Map:setViewPort(216, 0, self.w - 216, (self.map_h_stop or 80) - 16, 48, 48, nil, 36, do_bg)
 		elseif gfx.size == "32x32" then
-			Map:setViewPort(216, 36, self.w - 216, math.floor(self.h * 0.80) - 36, 32, 32, nil, 22, do_bg)
-			Map:resetTiles()
+			Map:setViewPort(216, 0, self.w - 216, (self.map_h_stop or 80) - 16, 32, 32, nil, 22, do_bg)
 		elseif gfx.size == "16x16" then
-			Map:setViewPort(216, 36, self.w - 216, math.floor(self.h * 0.80) - 36, 16, 16, "/data/font/FSEX300.ttf", 16, do_bg)
-			Map:resetTiles()
+			Map:setViewPort(216, 0, self.w - 216, (self.map_h_stop or 80) - 16, 16, 16, "/data/font/FSEX300.ttf", 16, do_bg)
 		end
 
 		Map.tiles.use_images = true
@@ -367,19 +381,19 @@ function _M:setupDisplayMode(reboot, mode)
 		if gfx.tiles == "shockbolt" then Map.tiles.nicer_tiles = true end
 		if gfx.tiles == "oldrpg" then Map.tiles.nicer_tiles = true end
 
-		-- Create the framebuffer
-		self.fbo = core.display.newFBO(Map.viewport.width, Map.viewport.height)
-		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 end end
-		if self.player then self.player:updateMainShader() end
-	end
-
-	if not mode or mode == "postinit" then
 		if self.level then
-			self.level.map:recreate()
+			if self.level.map.finished then
+				self.level.map:recreate()
+				self.level.map:moveViewSurround(self.player.x, self.player.y, 8, 8)
+			end
 			self:initTargeting()
-			self.level.map:moveViewSurround(self.player.x, self.player.y, 8, 8)
 		end
 		self:setupMiniMap()
+
+		-- Create the framebuffer
+		self.fbo = core.display.newFBO(Map.viewport.width, Map.viewport.height)
+		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 end end
+		if self.player then self.player:updateMainShader() end
 	end
 end
 
@@ -389,7 +403,7 @@ end
 
 
 function _M:setupMiniMap()
-	if self.level and self.level.map then self.level.map._map:setupMiniMapGridSize(4) end
+	if self.level and self.level.map and self.level.map.finished then self.level.map._map:setupMiniMapGridSize(4) end
 end
 
 function _M:save()
@@ -736,13 +750,13 @@ end
 function _M:displayDelayedLogDamage()
 	for src, tgts in pairs(self.delayed_log_damage) do
 		for target, dams in pairs(tgts) do
-			local flash = game.flash.NEUTRAL
-			if target == game.player then flash = game.flash.BAD end
-			if src == game.player then flash = game.flash.GOOD end
+--			local flash = game.flash.NEUTRAL
+--			if target == game.player then flash = game.flash.BAD end
+--			if src == game.player then flash = game.flash.GOOD end
 			if #dams.descs > 1 then
-				game.logSeen(target, flash, "%s hits %s for %s damage (total %0.2f).", src.name:capitalize(), target.name, table.concat(dams.descs, ", "), dams.total)
+				game.logSeen(target, "%s hits %s for %s damage (total %0.2f).", src.name:capitalize(), target.name, table.concat(dams.descs, ", "), dams.total)
 			else
-				game.logSeen(target, flash, "%s hits %s for %s damage.", src.name:capitalize(), target.name, table.concat(dams.descs, ", "))
+				game.logSeen(target, "%s hits %s for %s damage.", src.name:capitalize(), target.name, table.concat(dams.descs, ", "))
 			end
 
 			local rsrc = src.resolveSource and src:resolveSource() or src
@@ -852,9 +866,9 @@ function _M:display(nb_keyframes)
 		map:displayEmotes(nb_keyframe or 1)
 
 		-- Minimap display
-		self.minimap_bg:toScreen(0, 35, 200, 200)
+		self.minimap_bg:toScreen(0, 0, 200, 200)
 		self.minimap_scroll_x, self.minimap_scroll_y = util.bound(self.player.x - 25, 0, map.w - 50), util.bound(self.player.y - 25, 0, map.h - 50)
-		map:minimapDisplay(0, 35, self.minimap_scroll_x, self.minimap_scroll_y, 50, 50, 1)
+		map:minimapDisplay(0, 0, self.minimap_scroll_x, self.minimap_scroll_y, 50, 50, 1)
 
 		-- Mouse gestures
 		self.gestures:update()
@@ -862,10 +876,12 @@ function _M:display(nb_keyframes)
 	end
 
 	-- We display the player's interface
-	self.flash:toScreen(nb_keyframe)
-	if self.show_userchat then profile.chat:toScreen()
-	else self.logdisplay:toScreen()
-	end
+--	self.flash:toScreen(nb_keyframe)
+--	if self.show_userchat then profile.chat:toScreen()
+--	else self.logdisplay:toScreen()
+--	end
+	profile.chat:toScreen()
+	self.logdisplay:toScreen()
 
 	self.player_display:toScreen(nb_keyframes)
 	if self.show_npc_list then
@@ -901,7 +917,7 @@ function _M:onUnregisterDialog(d)
 	-- Clean up tooltip
 	self.tooltip_x, self.tooltip_y = nil, nil
 	self.tooltip2_x, self.tooltip2_y = nil, nil
-	if self.player then self.player:updateMainShader() end
+	if self.player then self.player:updateMainShader() self.player.changed = true end
 end
 
 function _M:setupCommands()
@@ -955,7 +971,12 @@ function _M:setupCommands()
 
 	self.key.any_key = function(sym)
 		-- Control resets the tooltip
-		if sym == self.key._LCTRL or sym == self.key._RCTRL then self.tooltip.old_tmx = nil end
+		if sym == self.key._LCTRL or sym == self.key._RCTRL then
+			self.player.changed = true
+			self.tooltip.old_tmx = nil
+		elseif sym == self.key._LSHIFT or sym == self.key._RSHIFT then
+			self.player.changed = true
+		end
 	end
 	self.key:addBinds
 	{
@@ -1129,11 +1150,7 @@ function _M:setupCommands()
 		end,
 
 		SHOW_MESSAGE_LOG = function()
-			if not self.show_userchat then
-				self.logdisplay:showLogDialog(nil, 0.6)
-			else
-				profile.chat:showLogDialog(nil, 0.6)
-			end
+			self:registerDialog(require("mod.dialogs.ShowChatLog").new("Message Log", 0.6, self.logdisplay, profile.chat))
 		end,
 
 		-- Show time
@@ -1193,8 +1210,8 @@ function _M:setupCommands()
 		end,
 
 		LOOK_AROUND = function()
-			self.flash:empty(true)
-			self.flash(self.flash.GOOD, "Looking around... (direction keys to select interesting things, shift+direction keys to move freely)")
+--			self.flash:empty(true)
+			self.log("Looking around... (direction keys to select interesting things, shift+direction keys to move freely)")
 			local co = coroutine.create(function() self.player:getTarget{type="hit", no_restrict=true, range=2000} end)
 			local ok, err = coroutine.resume(co)
 			if not ok and err then print(debug.traceback(co)) error(err) end
@@ -1244,6 +1261,7 @@ function _M:setupMouse(reset)
 		self.player:mouseHandleDefault(self.key, self.key == self.normal_key, button, mx, my, xrel, yrel, event)
 	end)
 	-- Scroll message log
+--[[
 	self.mouse:registerZone(self.logdisplay.display_x, self.logdisplay.display_y, self.w, self.h, function(button, mx, my, xrel, yrel, bx, by, event)
 		if self.show_userchat then
 			profile.chat.mouse:delegate(button, mx, my, xrel, yrel, bx, by, event)
@@ -1253,6 +1271,7 @@ function _M:setupMouse(reset)
 			if button == "left" then self.logdisplay:showLogDialog(nil, 0.6) end
 		end
 	end)
+]]
 	-- Use hotkeys with mouse
 	self.mouse:registerZone(self.hotkeys_display.display_x, self.hotkeys_display.display_y, self.w, self.h, function(button, mx, my, xrel, yrel, bx, by, event)
 		if event == "button" and button == "left" and self.zone and self.zone.wilderness then return end
@@ -1277,11 +1296,11 @@ function _M:setupMouse(reset)
 		if button == "left" then self:clickIcon(bx, by) end
 	end)
 	-- Tooltip over the player pane
-	self.mouse:registerZone(self.player_display.display_x, self.player_display.display_y, self.player_display.w, self.player_display.h, function(button, mx, my, xrel, yrel, bx, by, event)
+	self.mouse:registerZone(self.player_display.display_x, self.player_display.display_y, self.player_display.w, self.player_display.h - self.icons.h, function(button, mx, my, xrel, yrel, bx, by, event)
 		self.player_display.mouse:delegate(button, mx, my, xrel, yrel, bx, by, event)
 	end)
 	-- Move using the minimap
-	self.mouse:registerZone(0, 35, 200, 200, function(button, mx, my, xrel, yrel, bx, by, event)
+	self.mouse:registerZone(0, 0, 200, 200, function(button, mx, my, xrel, yrel, bx, by, event)
 		if button == "left" and not xrel and not yrel and event == "button" then
 			local tmx, tmy = math.floor(bx / 4), math.floor(by / 4)
 			self.player:mouseMove(tmx + self.minimap_scroll_x, tmy + self.minimap_scroll_y)
@@ -1505,6 +1524,7 @@ local _sep_vert = {core.display.loadImage("/data/gfx/ui/separator-vert.png")} _s
 local _sep_top = {core.display.loadImage("/data/gfx/ui/separator-top.png")} _sep_top.tex = {_sep_top[1]:glTexture()}
 local _sep_bottom = {core.display.loadImage("/data/gfx/ui/separator-bottom.png")} _sep_bottom.tex = {_sep_bottom[1]:glTexture()}
 local _sep_bottoml = {core.display.loadImage("/data/gfx/ui/separator-bottom_line_end.png")} _sep_bottoml.tex = {_sep_bottoml[1]:glTexture()}
+local _sep_left = {core.display.loadImage("/data/gfx/ui/separator-left.png")} _sep_left.tex = {_sep_left[1]:glTexture()}
 local _sep_leftl = {core.display.loadImage("/data/gfx/ui/separator-left_line_end.png")} _sep_leftl.tex = {_sep_leftl[1]:glTexture()}
 local _sep_rightl = {core.display.loadImage("/data/gfx/ui/separator-right_line_end.png")} _sep_rightl.tex = {_sep_rightl[1]:glTexture()}
 
@@ -1521,116 +1541,107 @@ function _M:displayUI()
 	local middle = self.w * 0.5
 	local bottom = self.h * 0.8
 	local bottom_h = self.h * 0.2
-	local icon_x = middle - (_talents_icon_w*2) / 2
-	local icon_x2 = middle + (_talents_icon_w*2) / 2
-	local mid_min = icon_x - (_sep_vert[2])
-	local mid_max = icon_x2
+	local icon_x = 0
+	local icon_y = self.h - (_talents_icon_h * 1)
+	local glow = (1+math.sin(core.game.getTime() / 500)) / 2 * 100 + 77
 
 	-- Icons
-	local x, y = icon_x, bottom + _sep_horiz[3] / 2
-	_talents_icon:toScreenFull(x + _talents_icon_w, y, _talents_icon_w, _talents_icon_h, _talents_icon_w, _talents_icon_h)
-	if not self.show_npc_list then _sel_icon:toScreenFull(x + _talents_icon_w, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end
-	y = y + _talents_icon_h
-	_actors_icon:toScreenFull(x + _talents_icon_w, y, _actors_icon_w, _actors_icon_h, _actors_icon_w, _actors_icon_h)
-	if self.show_npc_list then _sel_icon:toScreenFull(x + _talents_icon_w, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end
-	y = y + _talents_icon_h
-
-	local glow = (1+math.sin(core.game.getTime() / 500)) / 2 * 100 + 77
-	local x, y = icon_x, bottom + _sep_horiz[3] / 2
-	if self.logdisplay.changed then core.display.drawQuad(x, y, _sel_icon_w, _sel_icon_h, 139, 210, 77, glow) end
+	local x, y = icon_x, icon_y
+	_talents_icon:toScreenFull(x, y, _talents_icon_w, _talents_icon_h, _talents_icon_w, _talents_icon_h)
+	if not self.show_npc_list then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end
+	x = x + _talents_icon_w
+	_actors_icon:toScreenFull(x, y, _actors_icon_w, _actors_icon_h, _actors_icon_w, _actors_icon_h)
+	if self.show_npc_list then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end
+	x = x + _talents_icon_w
+
+--	if self.logdisplay.changed then core.display.drawQuad(x, y, _sel_icon_w, _sel_icon_h, 139, 210, 77, glow) end
+--	_log_icon:toScreenFull(x, y, _log_icon_w, _log_icon_h, _log_icon_w, _log_icon_h)
+--	if not self.show_userchat then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end
+--	x = x + _talents_icon_w
+
+--	if profile.chat.changed then core.display.drawQuad(x, y, _sel_icon_w, _sel_icon_h, 139, 210, 77, glow) end
+--	_chat_icon:toScreenFull(x, y, _chat_icon_w, _chat_icon_h, _chat_icon_w, _chat_icon_h)
+--	if self.show_userchat then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end
+
+--	x = 0
+--	y = y + _chat_icon_h
+--	x = x + _talents_icon_w
+
+	_inventory_icon:toScreenFull(x, y, _inventory_icon_w, _inventory_icon_h, _inventory_icon_w, _inventory_icon_h)
+	x = x + _talents_icon_w
+	_charsheet_icon:toScreenFull(x, y, _charsheet_icon_w, _charsheet_icon_h, _charsheet_icon_w, _charsheet_icon_h)
+	x = x + _talents_icon_w
+	_main_menu_icon:toScreenFull(x, y, _main_menu_icon_w, _main_menu_icon_h, _main_menu_icon_w, _main_menu_icon_h)
+	x = x + _talents_icon_w
 	_log_icon:toScreenFull(x, y, _log_icon_w, _log_icon_h, _log_icon_w, _log_icon_h)
-	if not self.show_userchat then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end
-	y = y + _log_icon_h
-	if profile.chat.changed then core.display.drawQuad(x, y, _sel_icon_w, _sel_icon_h, 139, 210, 77, glow) end
-	_chat_icon:toScreenFull(x, y, _chat_icon_w, _chat_icon_h, _chat_icon_w, _chat_icon_h)
-	if self.show_userchat then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end
-	y = y + _chat_icon_h
-
-	_inventory_icon:toScreenFull(x + _talents_icon_w/2, y, _inventory_icon_w, _inventory_icon_h, _inventory_icon_w, _inventory_icon_h) y = y + _inventory_icon_h
-	_charsheet_icon:toScreenFull(x + _talents_icon_w/2, y, _charsheet_icon_w, _charsheet_icon_h, _charsheet_icon_w, _charsheet_icon_h) y = y + _charsheet_icon_h
-	_main_menu_icon:toScreenFull(x + _talents_icon_w/2, y, _main_menu_icon_w, _main_menu_icon_h, _main_menu_icon_w, _main_menu_icon_h) y = y + _main_menu_icon_h
 
 	-- Separators
-	_sep_horiz.tex[1]:toScreenFull(0, 20, self.w, _sep_horiz[3], _sep_horiz.tex[2], _sep_horiz.tex[3])
-	_sep_horiz.tex[1]:toScreenFull(0, bottom - _sep_horiz[3] / 2, self.w, _sep_horiz[3], _sep_horiz.tex[2], _sep_horiz.tex[3])
+--	_sep_horiz.tex[1]:toScreenFull(0, 20, self.w, _sep_horiz[3], _sep_horiz.tex[2], _sep_horiz.tex[3])
+	_sep_horiz.tex[1]:toScreenFull(216, self.map_h_stop - _sep_horiz[3], self.w - 216, _sep_horiz[3], _sep_horiz.tex[2], _sep_horiz.tex[3])
 
-	_sep_vert.tex[1]:toScreenFull(mid_min, bottom, _sep_vert[2], bottom_h, _sep_vert.tex[2], _sep_vert.tex[3])
-	_sep_vert.tex[1]:toScreenFull(mid_max, bottom, _sep_vert[2], bottom_h, _sep_vert.tex[2], _sep_vert.tex[3])
+--	_sep_vert.tex[1]:toScreenFull(mid_min, bottom, _sep_vert[2], bottom_h, _sep_vert.tex[2], _sep_vert.tex[3])
+--	_sep_vert.tex[1]:toScreenFull(mid_max, bottom, _sep_vert[2], bottom_h, _sep_vert.tex[2], _sep_vert.tex[3])
 
-	_sep_vert.tex[1]:toScreenFull(200, 20, _sep_vert[2], bottom - 20, _sep_vert.tex[2], _sep_vert.tex[3])
+	_sep_vert.tex[1]:toScreenFull(200, 0, _sep_vert[2], self.h, _sep_vert.tex[2], _sep_vert.tex[3])
 
 	-- Ornaments
-	_sep_top.tex[1]:toScreenFull(mid_min - (-_sep_vert[2] + _sep_top[2]) / 2, bottom - 14, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3])
-	_sep_top.tex[1]:toScreenFull(mid_max - (-_sep_vert[2] + _sep_top[2]) / 2, bottom - 14, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3])
-	_sep_bottoml.tex[1]:toScreenFull(mid_min - (-_sep_vert[2] + _sep_bottoml[2]) / 2, self.h - _sep_bottoml[3], _sep_bottoml[2], _sep_bottoml[3], _sep_bottoml.tex[2], _sep_bottoml.tex[3])
-	_sep_bottoml.tex[1]:toScreenFull(mid_max - (-_sep_vert[2] + _sep_bottoml[2]) / 2, self.h - _sep_bottoml[3], _sep_bottoml[2], _sep_bottoml[3], _sep_bottoml.tex[2], _sep_bottoml.tex[3])
+--	_sep_top.tex[1]:toScreenFull(mid_min - (-_sep_vert[2] + _sep_top[2]) / 2, bottom - 14, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3])
+--	_sep_top.tex[1]:toScreenFull(mid_max - (-_sep_vert[2] + _sep_top[2]) / 2, bottom - 14, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3])
+--	_sep_bottoml.tex[1]:toScreenFull(mid_min - (-_sep_vert[2] + _sep_bottoml[2]) / 2, self.h - _sep_bottoml[3], _sep_bottoml[2], _sep_bottoml[3], _sep_bottoml.tex[2], _sep_bottoml.tex[3])
+--	_sep_bottoml.tex[1]:toScreenFull(mid_max - (-_sep_vert[2] + _sep_bottoml[2]) / 2, self.h - _sep_bottoml[3], _sep_bottoml[2], _sep_bottoml[3], _sep_bottoml.tex[2], _sep_bottoml.tex[3])
 
-	_sep_leftl.tex[1]:toScreenFull(0, 20 - _sep_leftl[3] / 2 + 7, _sep_leftl[2], _sep_leftl[3], _sep_leftl.tex[2], _sep_leftl.tex[3])
-	_sep_leftl.tex[1]:toScreenFull(0, bottom - _sep_leftl[3] / 2, _sep_leftl[2], _sep_leftl[3], _sep_leftl.tex[2], _sep_leftl.tex[3])
+--	_sep_leftl.tex[1]:toScreenFull(0, 20 - _sep_leftl[3] / 2 + 7, _sep_leftl[2], _sep_leftl[3], _sep_leftl.tex[2], _sep_leftl.tex[3])
+	_sep_left.tex[1]:toScreenFull(200 - 7, self.map_h_stop - 7 - _sep_left[3] / 2, _sep_left[2], _sep_left[3], _sep_left.tex[2], _sep_left.tex[3])
 
-	_sep_rightl.tex[1]:toScreenFull(self.w - _sep_rightl[2], 20 - _sep_rightl[3] / 2 + 7, _sep_rightl[2], _sep_rightl[3], _sep_rightl.tex[2], _sep_rightl.tex[3])
-	_sep_rightl.tex[1]:toScreenFull(self.w - _sep_rightl[2], bottom - _sep_rightl[3] / 2, _sep_rightl[2], _sep_rightl[3], _sep_rightl.tex[2], _sep_rightl.tex[3])
+--	_sep_rightl.tex[1]:toScreenFull(self.w - _sep_rightl[2], 20 - _sep_rightl[3] / 2 + 7, _sep_rightl[2], _sep_rightl[3], _sep_rightl.tex[2], _sep_rightl.tex[3])
+	_sep_rightl.tex[1]:toScreenFull(self.w - _sep_rightl[2], self.map_h_stop - _sep_left[3] / 2, _sep_rightl[2], _sep_rightl[3], _sep_rightl.tex[2], _sep_rightl.tex[3])
 
-	_sep_top.tex[1]:toScreenFull(200 - (_sep_top[2] - _sep_vert[2]) / 2, 20 - 7, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3])
-	_sep_bottom.tex[1]:toScreenFull(200 - (_sep_bottom[2] - _sep_vert[2]) / 2, bottom - 25, _sep_bottom[2], _sep_bottom[3], _sep_bottom.tex[2], _sep_bottom.tex[3])
+	_sep_top.tex[1]:toScreenFull(200 - (_sep_top[2] - _sep_vert[2]) / 2, - 7, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3])
+--	_sep_bottom.tex[1]:toScreenFull(200 - (_sep_bottom[2] - _sep_vert[2]) / 2, bottom - 25, _sep_bottom[2], _sep_bottom[3], _sep_bottom.tex[2], _sep_bottom.tex[3])
 
 end
 
 function _M:createSeparators()
-	local middle = self.w * 0.5
-	local bottom = self.h * 0.8
-	local bottom_h = self.h * 0.2
+	local icon_x = 0
+	local icon_y = self.h - (_talents_icon_h * 1)
 	self.icons = {
-		display_x = middle - (_talents_icon_w*2) / 2,
-		display_y = bottom + _sep_horiz[3] / 2,
-		w = _talents_icon_w*2,
-		h = 5*_talents_icon_h
+		display_x = icon_x,
+		display_y = icon_y,
+		w = 200,
+		h = self.h - icon_y,
 	}
 end
 
 function _M:clickIcon(bx, by)
-	if by < _talents_icon_h then
-		if bx >= _talents_icon_w then
-			self.show_npc_list = false
-			self.player.changed = true
-		else
-			self.show_userchat = false
-			self.logdisplay.changed = true
-		end
-	elseif by < 2*_talents_icon_h then
-		if bx >= _talents_icon_w then
-			self.show_npc_list = true
-			self.player.changed = true
-		else
-			self.show_userchat = true
-		end
-	elseif by < 3*_talents_icon_h then
+	if bx < _talents_icon_w then
+		self.show_npc_list = false
+		self.player.changed = true
+	elseif bx < 2*_talents_icon_w then
+		self.show_npc_list = true
+		self.player.changed = true
+	elseif bx < 3*_talents_icon_w then
 		self.key:triggerVirtual("SHOW_INVENTORY")
-	elseif by < 4*_talents_icon_h then
+	elseif bx < 4*_talents_icon_w then
 		self.key:triggerVirtual("SHOW_CHARACTER_SHEET")
-	elseif by < 5*_talents_icon_h then
+	elseif bx < 5*_talents_icon_w then
 		self.key:triggerVirtual("EXIT")
+	elseif bx < 6*_talents_icon_w then
+		self.key:triggerVirtual("SHOW_MESSAGE_LOG")
 	end
 end
 
 function _M:mouseIcon(bx, by)
-	if by < _talents_icon_h then
-		if bx >= _talents_icon_w then
-			self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display talents\nToggle with [tab]")
-		else
-			self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display game log\nToggle with [ctrl+space]")
-		end
-	elseif by < 2*_talents_icon_h then
-		if bx >= _talents_icon_w then
-			self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display creatures\nToggle with [tab]")
-		else
-			self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display community chat\nToggle with [ctrl+space]")
-		end
-	elseif by < 3*_talents_icon_h then
-		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Inventory")
-	elseif by < 4*_talents_icon_h then
-		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Character Sheet")
-	elseif by < 5*_talents_icon_h then
-		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Main menu")
+	if bx < _talents_icon_w then
+		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display talents\nToggle with #{bold}##GOLD#[tab]#LAST##{normal}#")
+	elseif bx < 2*_talents_icon_w then
+		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display creatures\nToggle with #{bold}##GOLD#[tab]#LAST##{normal}#")
+	elseif bx < 3*_talents_icon_w then
+		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "#{bold}##GOLD#I#LAST##{normal}#nventory")
+	elseif bx < 4*_talents_icon_w then
+		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "#{bold}##GOLD#C#LAST##{normal}#haracter Sheet")
+	elseif bx < 5*_talents_icon_w then
+		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Main menu (#{bold}##GOLD#Esc#LAST##{normal}#)")
+	elseif bx < 6*_talents_icon_w then
+		self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Show message/chat log (#{bold}##GOLD#ctrl+m#LAST##{normal}#)")
 	end
 end
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index fca6fca92985e321937993b4dff9bf416caacab2..6899a46f0fde5e1ccf4c2e50646bb6ea394911b4 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -219,7 +219,7 @@ function _M:act()
 	self.old_life = self.life
 
 	-- Clean log flasher
-	game.flash:empty()
+--	game.flash:empty()
 
 	-- Resting ? Running ? Otherwise pause
 	if not self:restStep() and not self:runStep() and self.player then
diff --git a/game/modules/tome/dialogs/ShowChatLog.lua b/game/modules/tome/dialogs/ShowChatLog.lua
new file mode 100644
index 0000000000000000000000000000000000000000..3f5a7c2d762693de589532ac66a8b5f653fd62dd
--- /dev/null
+++ b/game/modules/tome/dialogs/ShowChatLog.lua
@@ -0,0 +1,160 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011 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 Tab = require "engine.ui.Tab"
+local Mouse = require "engine.Mouse"
+local Slider = require "engine.ui.Slider"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init(title, shadow, log, chat)
+	local w = math.floor(game.w * 0.9)
+	local h = math.floor(game.h * 0.9)
+	Dialog.init(self, title, w, h)
+	if shadow then self.shadow = shadow end
+
+	self.log, self.chat = log, chat
+
+	local tabs = {}
+
+	local order = {}
+	local list = {}
+	for name, data in pairs(chat.channels) do list[#list+1] = name end
+	table.sort(list, function(a,b) if a == "global" then return 1 elseif b == "global" then return nil else return a < b end end)
+	order[#order+1] = {timestamp=log:getLogLast(), tab="__log"}
+
+	tabs[#tabs+1] = {top=0, left=0, ui = Tab.new{title="Game Log", fct=function() end, on_change=function() local i = #tabs self:switchTo(tabs[1]) end, default=true}, tab_channel="__log" }
+	for i, name in ipairs(list) do
+		local oname = name
+		local nb_users = 0
+		for _, _ in pairs(chat.channels[name].users) do nb_users = nb_users + 1 end
+		name = name:capitalize().." ("..nb_users..")"
+
+		local ii = i
+		tabs[#tabs+1] = {top=0, left=(#tabs==0) and 0 or tabs[#tabs].ui, ui = Tab.new{title=name, fct=function() end, on_change=function() local i = ii+1 self:switchTo(tabs[i]) end, default=false}, tab_channel=oname }
+		order[#order+1] = {timestamp=chat:getLogLast(oname), tab=oname}
+	end
+
+	self.start_y = tabs[1].ui.h + 5
+
+	self:loadUI(tabs)
+	self.tabs = tabs
+	self:setupUI()
+
+	self.scrollbar = Slider.new{size=self.h - 20, max=1, inverse=true}
+
+	table.sort(order, function(a,b) return a.timestamp > b.timestamp end)
+	self:switchTo(self.last_tab or "__log")
+end
+
+function _M:generate()
+	Dialog.generate(self)
+
+	-- Add UI controls
+	local tabs = self.tabs
+	self.key:addBinds{
+		MOVE_UP = function() self:setScroll(self.scroll - 1) end,
+		MOVE_DOWN = function() self:setScroll(self.scroll + 1) end,
+		ACCEPT = "EXIT",
+		EXIT = function() game:unregisterDialog(self) end,
+	}
+	self.key:addCommands{
+		_TAB = function() local sel = 1 for i=1, #tabs do if tabs[i].ui.selected then sel = i break end end self:switchTo(tabs[util.boundWrap(sel+1, 1, #tabs)]) end,
+		_HOME = function() self:setScroll(1) end,
+		_END = function() self:setScroll(self.max) end,
+		_PAGEUP = function() self:setScroll(self.scroll - self.max_display) end,
+		_PAGEDOWN = function() self:setScroll(self.scroll + self.max_display) end,
+	}
+end
+
+function _M:mouseEvent(button, x, y, xrel, yrel, bx, by, event)
+	Dialog.mouseEvent(self, button, x, y, xrel, yrel, bx, by, event)
+
+	if button == "wheelup" and event == "button" then self.key:triggerVirtual("MOVE_UP")
+	elseif button == "wheeldown" and event == "button" then self.key:triggerVirtual("MOVE_DOWN")
+	end
+end
+
+function _M:loadLog(log)
+	self.lines = {}
+	for i = #log, 1, -1 do
+		self.lines[#self.lines+1] = log[i]
+	end
+
+	self.max_h = self.ih - self.iy
+	self.max = #log
+	self.max_display = math.floor(self.max_h / self.font_h)
+
+	self.scrollbar.max = self.max - self.max_display + 1
+	self.scroll = nil
+	self:setScroll(self.max - self.max_display + 1)
+end
+
+function _M:switchTo(ui)
+	if type(ui) == "string" then for i, tab in ipairs(self.tabs) do if tab.tab_channel == ui then ui = tab end end end
+	if type(ui) == "string" then ui = self.tabs[1] end
+
+	for i, ui in ipairs(self.tabs) do ui.ui.selected = false end
+	ui.ui.selected = true
+	if ui.tab_channel == "__log" then
+		self:loadLog(self.log:getLog())
+	else
+		self:loadLog(self.chat:getLog(ui.tab_channel))
+	end
+	-- Set it on the class to persist between invocations
+	_M.last_tab = ui.tab_channel
+end
+
+function _M:setScroll(i)
+	local old = self.scroll
+	self.scroll = util.bound(i, 1, math.max(1, self.max - self.max_display + 1))
+	if self.scroll == old then return end
+
+	self.dlist = {}
+	local nb = 0
+	local old_style = self.font:getStyle()
+	for z = 1 + self.scroll, #self.lines do
+		local stop = false
+		local tstr = self.lines[z]
+		if not tstr then break end
+		local gen = self.font:draw(tstr, self.iw - 10, 255, 255, 255)
+		for i = 1, #gen do
+			self.dlist[#self.dlist+1] = gen[i]
+			nb = nb + 1
+			if nb >= self.max_display then stop = true break end
+		end
+		if stop then break end
+	end
+	self.font:setStyle(old_style)
+end
+
+function _M:innerDisplay(x, y, nb_keyframes)
+	local h = y + self.iy + self.start_y
+	for i = 1, #self.dlist do
+		local item = self.dlist[i]
+		if self.shadow then item._tex:toScreenFull(x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow) end
+		item._tex:toScreenFull(x, h, item.w, item.h, item._tex_w, item._tex_h)
+		h = h + self.font_h
+	end
+
+	self.scrollbar.pos = self.scrollbar.max - self.scroll + 1
+	self.scrollbar:display(x + self.iw - self.scrollbar.w, y)
+end