diff --git a/game/engines/default/engine/Module.lua b/game/engines/default/engine/Module.lua
index 778112424a29b3ba897b837e844c6a9936e6b22a..9a854f028fe07d8ee6e78822fe26477f88232e4c 100644
--- a/game/engines/default/engine/Module.lua
+++ b/game/engines/default/engine/Module.lua
@@ -254,7 +254,7 @@ function _M:listVaultSavesForCurrent()
 end
 
 --- List all available addons
-function _M:loadAddons(mod)
+function _M:listAddons(mod, ignore_compat)
 	local adds = {}
 	local load = function(dir, teaa)
 		local add_def = loadfile(dir.."/init.lua")
@@ -263,9 +263,11 @@ function _M:loadAddons(mod)
 			setfenv(add_def, add)
 			add_def()
 
-			if engine.version_string(add.version) == engine.version_string(mod.version) and add.for_module == mod.short_name then
+			if (ignore_compat or engine.version_string(add.version) == engine.version_string(mod.version)) and add.for_module == mod.short_name then
 				add.dir = dir
 				add.teaa = teaa
+				add.natural_compatible = engine.version_string(add.version) == engine.version_string(mod.version)
+				add.version_txt = ("%d.%d.%d"):format(add.version[1], add.version[2], add.version[3])
 				adds[#adds+1] = add
 			end
 		end
@@ -287,6 +289,28 @@ function _M:loadAddons(mod)
 	end end
 
 	table.sort(adds, function(a, b) return a.weight < b.weight end)
+	return adds
+end
+
+function _M:loadAddons(mod)
+	local adds = self:listAddons(mod, true)
+
+	-- Filter based on settings
+	for i = #adds, 1, -1 do
+		local add = adds[i]
+		if config.settings.addons[add.for_module] and config.settings.addons[add.for_module][add.short_name] ~= nil then
+			-- Forbidden by config
+			if config.settings.addons[add.for_module][add.short_name] == false then
+				print("Removing addon"..add.short_name..": not allowed by config")
+				table.remove(adds, i)
+			end
+		else
+			-- Forbidden by version
+			if not add.natural_compatible then
+				table.remove(adds, i)
+			end
+		end
+	end
 
 	mod.addons = {}
 	for i, add in ipairs(adds) do
diff --git a/game/engines/default/engine/init.lua b/game/engines/default/engine/init.lua
index 114e4a8a6aa39ef35976cee13caec33c945eba42..c16dfd24d5a6acd4b4cd8a213718ec12f3d9c945 100644
--- a/game/engines/default/engine/init.lua
+++ b/game/engines/default/engine/init.lua
@@ -60,6 +60,7 @@ display_fps = 30
 gamma_correction = 120
 mouse_move = true
 chat.filter = {}
+addons = {}
 ]]
 for i, file in ipairs(fs.list("/settings/")) do
 	if file:find(".cfg$") then
diff --git a/game/engines/default/modules/boot/dialogs/Addons.lua b/game/engines/default/modules/boot/dialogs/Addons.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8f6891e9ab8197c8c33eaa10178672beb28b5d85
--- /dev/null
+++ b/game/engines/default/modules/boot/dialogs/Addons.lua
@@ -0,0 +1,143 @@
+-- TE4 - T-Engine 4
+-- 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 Module = require "engine.Module"
+local Dialog = require "engine.ui.Dialog"
+local ListColumns = require "engine.ui.ListColumns"
+local Textzone = require "engine.ui.Textzone"
+local Separator = require "engine.ui.Separator"
+local Checkbox = require "engine.ui.Checkbox"
+local Button = require "engine.ui.Button"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init()
+	Dialog.init(self, "Configure Addons", game.w * 0.8, game.h * 0.8)
+
+	self.c_compat = Checkbox.new{default=false, width=math.floor(self.iw / 3 - 40), title="Show incompatible", on_change=function() self:switch() end}
+
+	self:generateList()
+
+	self.c_list = ListColumns.new{width=math.floor(self.iw / 3 - 10), height=self.ih - 10 - self.c_compat.h, scrollbar=true, columns={
+		{name="Game Module", width=80, display_prop="name"},
+		{name="Version", width=20, display_prop="version_txt"},
+	}, list=self.list, fct=function(item) end, select=function(item, sel) self:select(item) end}
+
+	self.c_adds = ListColumns.new{width=math.floor(self.iw * 2 / 3 - 10), height=self.ih - 10 - self.c_compat.h, scrollbar=true, columns={
+		{name="Addon", width=60, display_prop="long_name"},
+		{name="Active", width=20, display_prop=function(item) 
+			if config.settings.addons[item.for_module] and config.settings.addons[item.for_module][item.short_name] ~= nil then
+				return (config.settings.addons[item.for_module][item.short_name] and "#LIGHT_GREEN#Manual: Active" or "#LIGHT_RED#Manual: Disabled"):toTString()
+			else
+				return (item.natural_compatible and "#LIGHT_GREEN#Auto: Active" or "#LIGHT_RED#Auto: Incompatible"):toTString()
+			end
+		end},
+		{name="Version", width=20, display_prop="version_txt"},
+	}, list={}, fct=function(item) self:switchAddon(item) end, select=function(item, sel) self:select(item) end}
+
+	self:loadUI{
+		{left=0, top=0, ui=self.c_list},
+		{right=0, top=0, ui=self.c_adds},
+		{left=0, bottom=0, ui=self.c_compat},
+		{left=self.c_list.w + 5, top=5, ui=Separator.new{dir="horizontal", size=self.ih - 10}},
+	}
+	self:setFocus(self.c_list)
+	self:setupUI()
+
+	self:select(self.list[1])
+
+	self.key:addBinds{
+		EXIT = function() game:unregisterDialog(self) end,
+	}
+end
+
+function _M:on_register()
+	if #self.list == 1 then
+		game:unregisterDialog(self)
+		self.list[1]:fct()
+	end
+end
+
+function _M:select(item)
+	if item and item.adds and self.c_adds then
+		self.c_adds.list = item.adds
+		self.c_adds:generate()
+	end
+end
+
+function _M:switchAddon(item)
+	config.settings.addons[item.for_module] = config.settings.addons[item.for_module] or {}
+	local v = config.settings.addons[item.for_module][item.short_name]
+	if v == nil then config.settings.addons[item.for_module][item.short_name] = true
+	elseif v == true then config.settings.addons[item.for_module][item.short_name] = false
+	elseif v == false then config.settings.addons[item.for_module][item.short_name] = nil
+	end
+	self.c_adds:drawItem(item)
+
+	local lines = {}
+	lines[#lines+1] = ("addons = {}"):format(w)
+	for mod, adds in pairs(config.settings.addons) do
+		lines[#lines+1] = ("addons[%q] = {}"):format(mod)
+		for k, v in pairs(adds) do
+			lines[#lines+1] = ("addons[%q][%q] = %s"):format(mod, k, v and "true" or "false")
+		end
+	end
+
+	game:saveSettings("addons", table.concat(lines, "\n"))
+end
+
+function _M:generateList()
+	local list = Module:listModules(self.c_compat.checked)
+	self.list = {}
+	for i = 1, #list do
+		for j, mod in ipairs(list[i].versions) do
+			if j > 1 then break end
+			if not mod.is_boot and (not mod.show_only_on_cheat or config.settings.cheat) then
+				mod.name = tstring{{"font","bold"}, {"color","GOLD"}, mod.name, {"font","normal"}}
+				mod.fct = function(mod)
+					if mod.no_get_name then
+						Module:instanciate(mod, "player", true, false)
+					else
+						game:registerDialog(require('engine.dialogs.GetText').new("Enter your character's name", "Name", 2, 25, function(text)
+							local savename = text:gsub("[^a-zA-Z0-9_-.]", "_")
+							if fs.exists(("/%s/save/%s/game.teag"):format(mod.short_name, savename)) then
+								Dialog:yesnoPopup("Overwrite character?", "There is already a character with this name, do you want to overwrite it?", function(ret)
+									if not ret then Module:instanciate(mod, text, true) end
+								end, "No", "Yes")
+							else
+								Module:instanciate(mod, text, true)
+							end
+						end))
+					end
+				end
+				mod.version_txt = ("%d.%d.%d"):format(mod.version[1], mod.version[2], mod.version[3])
+				mod.adds = Module:listAddons(mod, true)
+
+				table.insert(self.list, mod)
+			end
+		end
+	end
+end
+
+function _M:switch()
+	self:generateList()
+	self.c_list.list = self.list
+	self.c_list:generate()
+end
diff --git a/game/engines/default/modules/boot/dialogs/MainMenu.lua b/game/engines/default/modules/boot/dialogs/MainMenu.lua
index 0c894238f703c5f579024b018c969a58ddf3c1eb..00c2885da59773f594068f28ff4c8033c8db4ec7 100644
--- a/game/engines/default/modules/boot/dialogs/MainMenu.lua
+++ b/game/engines/default/modules/boot/dialogs/MainMenu.lua
@@ -36,6 +36,7 @@ function _M:init()
 	l[#l+1] = {name="Load Game", fct=function() game:registerDialog(require("mod.dialogs.LoadGame").new()) end}
 	l[#l+1] = {name="Player Profile", fct=function() game:registerDialog(require("mod.dialogs.Profile").new()) end}
 	l[#l+1] = {name="View High Scores", fct=function() game:registerDialog(require("mod.dialogs.ViewHighScores").new()) end}
+	l[#l+1] = {name="Addons", fct=function() game:registerDialog(require("mod.dialogs.Addons").new()) end}
 	if config.settings.install_remote then l[#l+1] = {name="Install Module", fct=function() end} end
 	if config.settings.update_remote then l[#l+1] = {name="Update", fct=function() game:registerDialog(require("mod.dialogs.UpdateAll").new()) end} end
 	l[#l+1] = {name="Options", fct=function()