diff --git a/game/engines/default/data/keybinds/move.lua b/game/engines/default/data/keybinds/move.lua
index d78305859a8483ef7b07d3e6cd3dc9bdc25a5f39..b8a9406c6c2238e0f023ba1a16908586b7607efd 100644
--- a/game/engines/default/data/keybinds/move.lua
+++ b/game/engines/default/data/keybinds/move.lua
@@ -135,3 +135,29 @@ defineAction{
 	group = "movement",
 	name = _t"Auto-explore",
 }
+
+-- Character movements with classic WASD
+defineAction{
+	default = { "sym:_a:false:false:false:false", "sym:_LEFT:false:false:false:false" },
+	type = "MOVE_WASD_LEFT", updown=true,
+	group = _t"movement",
+	name = _t"Move left (WASD directions)",
+}
+defineAction{
+	default = { "sym:_d:false:false:false:false", "sym:_RIGHT:false:false:false:false" },
+	type = "MOVE_WASD_RIGHT", updown=true,
+	group = _t"movement",
+	name = _t"Move right (WASD directions)",
+}
+defineAction{
+	default = { "sym:_w:false:false:false:false", "sym:_UP:false:false:false:false" },
+	type = "MOVE_WASD_UP", updown=true,
+	group = _t"movement",
+	name = _t"Move up (WASD directions)",
+}
+defineAction{
+	default = { "sym:_s:false:false:false:false", "sym:_DOWN:false:false:false:false" },
+	type = "MOVE_WASD_DOWN", updown=true,
+	group = _t"movement",
+	name = _t"Move down (WASD directions)",
+}
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 306f4b2fb05b38964ec3d0bfc854da15718d6afe..33edc9c9dd657ace7491902379a77c13378e5964 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -2481,9 +2481,40 @@ do return end
 		self.player:activateHotkey(i)
 	end, function() return self.player.allow_talents_worldmap end))
 
+	self:setupWASD()
 	self.key:setCurrent()
 end
 
+function _M:setupWASD()
+	self.wasd_state = {}
+	local function handle_wasd()
+		local ws = self.wasd_state
+		if     ws.left  and ws.up   then self.key:triggerVirtual("MOVE_LEFT_UP")
+		elseif ws.right and ws.up   then self.key:triggerVirtual("MOVE_RIGHT_UP")
+		elseif ws.left  and ws.down then self.key:triggerVirtual("MOVE_LEFT_DOWN")
+		elseif ws.right and ws.down then self.key:triggerVirtual("MOVE_RIGHT_DOWN")
+		elseif ws.right             then self.key:triggerVirtual("MOVE_RIGHT")
+		elseif ws.left              then self.key:triggerVirtual("MOVE_LEFT")
+		elseif ws.up                then self.key:triggerVirtual("MOVE_UP")
+		elseif ws.down              then self.key:triggerVirtual("MOVE_DOWN")
+		end
+	end
+
+	if config.settings.tome.use_wasd then
+		self.key:addBinds{
+			MOVE_WASD_UP    = function(sym, ctrl, shift, alt, meta, unicode, isup, key) if isup then handle_wasd() end self.wasd_state.up = not isup and true or false end,
+			MOVE_WASD_DOWN  = function(sym, ctrl, shift, alt, meta, unicode, isup, key) if isup then handle_wasd() end self.wasd_state.down = not isup and true or false end,
+			MOVE_WASD_LEFT  = function(sym, ctrl, shift, alt, meta, unicode, isup, key) if isup then handle_wasd() end self.wasd_state.left = not isup and true or false end,
+			MOVE_WASD_RIGHT = function(sym, ctrl, shift, alt, meta, unicode, isup, key) if isup then handle_wasd() end self.wasd_state.right = not isup and true or false end,
+		}
+	else
+		self.key:removeBind("MOVE_WASD_UP")
+		self.key:removeBind("MOVE_WASD_DOWN")
+		self.key:removeBind("MOVE_WASD_LEFT")
+		self.key:removeBind("MOVE_WASD_RIGHT")
+	end
+end
+
 function _M:setupMouse(reset)
 	if reset == nil or reset then self.mouse:reset() end
 
diff --git a/game/modules/tome/dialogs/GameOptions.lua b/game/modules/tome/dialogs/GameOptions.lua
index dae44afe83321842c33a513eab5b7cd7c68aa5c5..c99f7238df2188ee7e36502ec545a1203a584456 100644
--- a/game/modules/tome/dialogs/GameOptions.lua
+++ b/game/modules/tome/dialogs/GameOptions.lua
@@ -449,6 +449,16 @@ function _M:generateListUi()
 		self.c_list:drawItem(item)
 	end,}
 
+	local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text=_t"Enable the WASD movement keys. Can be used to move diagonaly by pressing two directions at once.#WHITE#":toTString()}
+	list[#list+1] = { zone=zone, name=_t"#GOLD##{bold}#Enable WASD movement keys#WHITE##{normal}#":toTString(), status=function(item)
+		return tostring(config.settings.tome.use_wasd and "enabled" or "disabled")
+	end, fct=function(item)
+		config.settings.tome.use_wasd = not config.settings.tome.use_wasd
+		game:saveSettings("tome.use_wasd", ("tome.use_wasd = %s\n"):format(tostring(config.settings.tome.use_wasd)))
+		self.c_list:drawItem(item)
+		if self:isTome() then game:setupWASD() end
+	end,}
+
 	local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text=(_t"Sharpen Visuals, set to 0 to disable.#WHITE#"):toTString()}
 	list[#list+1] = { zone=zone, name=(_t"#GOLD##{bold}#Sharpen Visuals#WHITE##{normal}#"):toTString(), status=function(item)
 		return tostring((config.settings.tome.sharpen_display or 0))
diff --git a/game/modules/tome/settings.lua b/game/modules/tome/settings.lua
index 29c5b45fa7d865842cc0886076bb59b87f7e6352..1a947868d7058d50eb8118786162ceac28aa9aa2 100644
--- a/game/modules/tome/settings.lua
+++ b/game/modules/tome/settings.lua
@@ -59,6 +59,7 @@ if type(config.settings.tome.tinker_auto_switch) == "nil" then config.settings.t
 if type(config.settings.tome.quest_popup) == "nil" then config.settings.tome.quest_popup = true end
 if type(config.settings.tome.show_cloak_hoods) == "nil" then config.settings.tome.show_cloak_hoods = false end
 if type(config.settings.tome.upload_charsheet) == "nil" then config.settings.tome.upload_charsheet = true end
+if type(config.settings.tome.use_wasd) == "nil" then config.settings.tome.use_wasd = true end
 if not config.settings.tome.fonts then config.settings.tome.fonts = {type="fantasy", size="normal"} end
 if not config.settings.tome.ui_theme3 then config.settings.tome.ui_theme3 = "dark" end
 if not config.settings.tome.uiset_mode then config.settings.tome.uiset_mode = "Minimalist" end