diff --git a/TODO b/TODO
index 88d525e8..d99b7181 100644
--- a/TODO
+++ b/TODO
@@ -2,14 +2,13 @@
 High priority TODO in order (before first public disclose)
 
 [bart] tab widgets
-[bart] multiline rich text widget
 [bart] chat with tabs
 [bart] scrollbar
 [bart] scrollable widgets
 [bart] complete miniwindow (close, minimize, resize)
 [bart] move windows
 [bart] add top menu buttons
-[bart] console history, scrolling
+[bart] console scrolling
 [bart] modules managment interface
 [bart] adjust interface design
 
@@ -34,7 +33,6 @@ Low priority TODO
 [bart] load modules from zip packages
 [bart] create a class for reading binary files
 [bart] rework lua/c++ logger
-[bart] save lists on config manager
 [bart] make protocol class compatible with old tibia protocols
 
 == Graphics
@@ -42,20 +40,19 @@ Low priority TODO
 [bart] cache renders into framebuffers
 [bart] use hardware buffer
 [bart] use indices
-[bart] change mouse icon
 
 == Lua
 [bart] make possible to bind non LuaObject derived classes on lua engine (for usage with Point,Rect,Color,Size)
-[bart] bind every global lua function in static classes
 [bart] review usage of x,y/width,height in lua instead of point/size
 
 == Platform
 [bart] port to MacOs and iphone
+[bart] KeyDown, KeyText events
 change win32 mouse cursor icon
 
 == UI
 [bart] fix massive hotkeys when holding down a key
-[bart] horizontal box layout
+[bart] multiline rich text widget
 [bart] move layout proprieties to widget style
 [bart] multiline text editor widget
 [bart] create UIMessageBox, UIToolTip and UIInputBox
@@ -66,7 +63,7 @@ change win32 mouse cursor icon
 [bart] reapply anchor styles when adding new childs
 [bart] ui text selection
 [bart] make set of background/icon/image width alone work
-[bart] check for recursive anchors to print a error and avoid crashes
+[bart] check for recursive anchors and print a error instead of crashing
 
 == Client modules
 [bart] make possible to reload modules
diff --git a/modules/addon_terminal/terminal.lua b/modules/addon_terminal/terminal.lua
index 43896b17..4d661b95 100644
--- a/modules/addon_terminal/terminal.lua
+++ b/modules/addon_terminal/terminal.lua
@@ -6,6 +6,7 @@ local LogColors = { [LogInfo] = 'white',
                     [LogError] = 'red' }
 local MaxLogLines = 80
 local LabelHeight = 16
+local MaxHistory = 1000
 
 -- private variables
 local terminalWidget
@@ -109,6 +110,8 @@ function Terminal.init()
   terminalButton = TopMenu.addButton('terminalButton', 'Terminal (Ctrl + T)', '/core_styles/icons/terminal.png', Terminal.toggle)
   Hotkeys.bind('Ctrl+T', Terminal.toggle)
 
+  commandHistory = Settings.getList('terminal-history')
+
   commandLineEdit = terminalWidget:getChildById('commandLineEdit')
   Hotkeys.bind('Up', function() navigateCommand(1) end, commandLineEdit)
   Hotkeys.bind('Down', function() navigateCommand(-1) end, commandLineEdit)
@@ -122,6 +125,7 @@ function Terminal.init()
 end
 
 function Terminal.terminate()
+  Settings.setList('terminal-history', commandHistory)
   Hotkeys.unbind('Ctrl+T')
   Logger.setOnLog(nil)
   terminalButton:destroy()
@@ -186,6 +190,9 @@ function Terminal.executeCommand(command)
 
   -- add new command to history
   table.insert(commandHistory, command)
+  if #commandHistory > MaxHistory then
+    table.remove(commandHistory, 1)
+  end
 
   -- add command line
   Terminal.addLine(">> " .. command, "#ffffff")
diff --git a/modules/client_topmenu/topmenu.lua b/modules/client_topmenu/topmenu.lua
index d1c5de34..72406cbe 100644
--- a/modules/client_topmenu/topmenu.lua
+++ b/modules/client_topmenu/topmenu.lua
@@ -4,6 +4,7 @@ TopMenu = {}
 local topMenu
 local leftButtonsPanel
 local rightButtonsPanel
+local gameButtonsPanel
 
 -- private functions
 local function onLogout()
@@ -19,6 +20,7 @@ function TopMenu.init()
   topMenu = displayUI('topmenu.otui')
   leftButtonsPanel = topMenu:getChildById('leftButtonsPanel')
   rightButtonsPanel = topMenu:getChildById('rightButtonsPanel')
+  gameButtonsPanel = topMenu:getChildById('gameButtonsPanel')
 
   TopMenu.addRightButton('logoutButton', 'Logout (Ctrl+Q)', '/core_styles/icons/logout.png', onLogout)
   Hotkeys.bind('Ctrl+Q', onLogout)
@@ -51,6 +53,15 @@ function TopMenu.addButton(id, description, icon, callback, right)
   return button
 end
 
+function TopMenu.addGameButton(id, description, icon, callback)
+  local button = createWidget('GameTopButton', gameButtonsPanel)
+  button:setId(id)
+  button:setTooltip(description)
+  button:setIcon(resolvepath(icon, 2))
+  button.onClick = callback
+  return button
+end
+
 function TopMenu.addLeftButton(id, description, icon, callback)
   return TopMenu.addButton(id, description, icon, callback, false)
 end
diff --git a/modules/client_topmenu/topmenu.otui b/modules/client_topmenu/topmenu.otui
index 6a9b82b3..fdd5cebe 100644
--- a/modules/client_topmenu/topmenu.otui
+++ b/modules/client_topmenu/topmenu.otui
@@ -1,22 +1,45 @@
 TopButton < UIButton
   size: 26 26
-  image-color: white
   image-source: /core_styles/images/top_button.png
   image-clip: 0 0 26 26
   image-border: 3
+  image-color: #ffffffff
+  icon-color: #ffffffff
 
   $hover:
-    image-source: /core_styles/images/top_button.png
+    image-color: #ffffff99
     image-clip: 26 0 26 26
-    image-border: 3
 
   $pressed:
-    image-source: /core_styles/images/top_button.png
     image-clip: 52 0 26 26
-    image-border: 3
 
   $disabled:
-    image-color: #ffffff66
+    image-color: #ffffff44
+    icon-color: #ffffff44
+
+GameTopButton < UIButton
+  size: 26 26
+  image-source: /core_styles/images/top_button2.png
+  image-clip: 26 0 26 26
+  image-color: #ffffff22
+  icon-color: #ffffffff
+  image-border: 3
+
+  $hover:
+    image-clip: 0 0 26 26
+    image-color: #ffffffff
+    icon-color: #ffffffff
+
+  $first:
+    anchors.top: parent.top
+    anchors.left: parent.left
+    margin-top: 4
+    margin-left: 6
+
+  $!first:
+    anchors.top: prev.top
+    anchors.left: prev.right
+    margin-left: 6
 
 TopLeftButton < TopButton
   $first:
@@ -54,6 +77,13 @@ TopPanel
     anchors.top: parent.top
     anchors.bottom: parent.bottom
     anchors.left: parent.left
+    width: 150
+
+  Panel
+    id: gameButtonsPanel
+    anchors.top: parent.top
+    anchors.bottom: parent.bottom
+    anchors.left: prev.right
     anchors.right: next.left
 
   Panel
diff --git a/modules/core_lib/settings.lua b/modules/core_lib/settings.lua
index 3a951821..cd2a51b2 100644
--- a/modules/core_lib/settings.lua
+++ b/modules/core_lib/settings.lua
@@ -10,6 +10,8 @@ local function convertSettingValue(value)
       return sizetostring(value)
     elseif value.r then
       return colortostring(value)
+    else
+      return value
     end
   elseif value == nil then
     return ''
@@ -30,6 +32,10 @@ function Settings.set(key, value)
   g_configs.set(key, convertSettingValue(value))
 end
 
+function Settings.setList(key, list)
+  g_configs.setList(key, list)
+end
+
 function Settings.setDefault(key, value)
   if Settings.exists(key) then return false end
   Settings.set(key, value)
@@ -43,6 +49,10 @@ function Settings.get(key, default)
   return g_configs.get(key)
 end
 
+function Settings.getList(key)
+  return g_configs.getList(key)
+end
+
 function Settings.getString(key, default)
   return Settings.get(key, default)
 end
diff --git a/modules/core_styles/icons/skills.png b/modules/core_styles/icons/skills.png
index 0c46c9b9..52deb107 100644
Binary files a/modules/core_styles/icons/skills.png and b/modules/core_styles/icons/skills.png differ
diff --git a/modules/core_styles/icons/viplist.png b/modules/core_styles/icons/viplist.png
new file mode 100644
index 00000000..2bedcaff
Binary files /dev/null and b/modules/core_styles/icons/viplist.png differ
diff --git a/modules/core_styles/images/mini_window.png b/modules/core_styles/images/mini_window.png
index d91d3c88..d3123826 100644
Binary files a/modules/core_styles/images/mini_window.png and b/modules/core_styles/images/mini_window.png differ
diff --git a/modules/core_styles/images/top_button.png b/modules/core_styles/images/top_button.png
index 6a8ef9d0..d0480416 100644
Binary files a/modules/core_styles/images/top_button.png and b/modules/core_styles/images/top_button.png differ
diff --git a/modules/core_styles/images/top_button2.png b/modules/core_styles/images/top_button2.png
new file mode 100644
index 00000000..7820d506
Binary files /dev/null and b/modules/core_styles/images/top_button2.png differ
diff --git a/modules/core_widgets/uicombobox.lua b/modules/core_widgets/uicombobox.lua
index a6f13e7e..ef08dbfa 100644
--- a/modules/core_widgets/uicombobox.lua
+++ b/modules/core_widgets/uicombobox.lua
@@ -2,16 +2,16 @@ UIComboBox = extends(UIWidget)
 
 function UIComboBox.create()
   local combobox = UIComboBox.internalCreate()
-  combobox.options = {}
-  combobox.currentIndex = -1
+  combobox.m_options = {}
+  combobox.m_currentIndex = -1
   return combobox
 end
 
 function UIComboBox:setCurrentOption(text)
-  if not self.options then return end
-  for i,v in ipairs(self.options) do
-    if v.text == text and self.currentIndex ~= i then
-      self.currentIndex = i
+  if not self.m_options then return end
+  for i,v in ipairs(self.m_options) do
+    if v.text == text and self.m_currentIndex ~= i then
+      self.m_currentIndex = i
       self:setText(text)
       self:onOptionChange(text, data)
       return
@@ -20,15 +20,15 @@ function UIComboBox:setCurrentOption(text)
 end
 
 function UIComboBox:addOption(text, data)
-  table.insert(self.options, { text = text, data = data })
-  local index = #self.options
+  table.insert(self.m_options, { text = text, data = data })
+  local index = #self.m_options
   if index == 1 then self:setCurrentOption(text) end
   return index
 end
 
 function UIComboBox:onMousePress(mousePos, mouseButton)
   local menu = createWidget(self:getStyleName() .. 'PopupMenu', self)
-  for i,v in ipairs(self.options) do
+  for i,v in ipairs(self.m_options) do
     menu:addOption(v.text, function() self:setCurrentOption(v.text) end)
   end
   menu:setWidth(self:getWidth())
diff --git a/modules/core_widgets/uimessagebox.lua b/modules/core_widgets/uimessagebox.lua
new file mode 100644
index 00000000..2c81a7cb
--- /dev/null
+++ b/modules/core_widgets/uimessagebox.lua
@@ -0,0 +1,23 @@
+UIMessageBox = extends(UIWindow)
+
+function UIMessageBox.create(title, message)
+  local messagebox = UIMessageBox.internalCreate()
+
+  messagebox:setText(title)
+  local messageLabel = self:getChildById('messageLabel')
+  label:setText(message)
+  label:resizeToText()
+
+  window:setWidth(math.max(label:getWidth() + self:getPaddingLeft() + self:getPaddingRight(), self:getWidth()))
+  window:setHeight(label:getHeight() + self:getPaddingTop() + self:getPaddingBottom())
+
+  return messagebox
+end
+
+function UIMessageBox:setTitle(title)
+end
+
+function UIMessageBox:setMessage(message)
+end
+
+function
\ No newline at end of file
diff --git a/modules/core_widgets/uiprogressbar.lua b/modules/core_widgets/uiprogressbar.lua
index 404f50e3..5d7cb3fa 100644
--- a/modules/core_widgets/uiprogressbar.lua
+++ b/modules/core_widgets/uiprogressbar.lua
@@ -4,19 +4,28 @@ function UIProgressBar.create()
   local progressbar = UIProgressBar.internalCreate()
   progressbar:setFocusable(false)
   progressbar:setPhantom(true)
-  progressbar.percent = 0
-  progressbar:setBackgroundSize({width = 1, height = 1})
+  progressbar.m_percent = 0
+  progressbar:updateBackground()
   return progressbar
 end
 
 function UIProgressBar:setPercent(percent)
-  self:setBackgroundHeight(self:getHeight())
-  local width = (percent * self:getWidth())/100
-  if width == 0 then width = 1 end
-  self:setBackgroundWidth(width)
-  self.percent = percent
+  self.m_percent = percent
+  self:updateBackground()
 end
 
+
 function UIProgressBar:getPercent()
-  return self.percent
+  return self.m_percent
+end
+
+function UIProgressBar:updateBackground()
+  local width = math.max((self.m_percent * self:getWidth())/100, 1)
+  local height = self:getHeight()
+  self:setBackgroundSize({width=width, height=height})
+end
+
+
+function UIProgressBar:onGeometryChange(oldRect, newRect)
+  self:updateBackground()
 end
diff --git a/modules/game/game.otmod b/modules/game/game.otmod
index ec8c8334..cc5d2814 100644
--- a/modules/game/game.otmod
+++ b/modules/game/game.otmod
@@ -7,9 +7,9 @@ Module
   dependencies:
     - game_healthbar
     - game_inventory
-    - game_skills
+    //- game_skills
     - game_textmessage
-    //- game_viplist
+    - game_viplist
     - game_console
     - game_outfit
     - game_containers
diff --git a/modules/game_skills/skills.lua b/modules/game_skills/skills.lua
index 93f748d7..52f00567 100644
--- a/modules/game_skills/skills.lua
+++ b/modules/game_skills/skills.lua
@@ -43,8 +43,7 @@ end
 -- public functions
 function Skills.create()
   skillWindow = displayUI('skills.otui', { parent = Game.gameRightPanel })
-  --skillsButton = TopMenu.addButton('skillsButton', 'Skills (Ctrl+S)', '/core_styles/icons/skills.png', Skills.toggle)
-  --skillsButton:setWidth(32)
+  skillsButton = TopMenu.addGameButton('skillsButton', 'Skills (Ctrl+S)', '/core_styles/icons/skills.png', Skills.toggle)
 end
 
 function Skills.destroy()
diff --git a/modules/game_viplist/viplist.lua b/modules/game_viplist/viplist.lua
index 4747d1cb..6ec5d994 100644
--- a/modules/game_viplist/viplist.lua
+++ b/modules/game_viplist/viplist.lua
@@ -7,6 +7,8 @@ local addVipWindow = nil
 -- public functions
 function VipList.create()
   vipWindow = displayUI('viplist.otui', { parent = Game.gameRightPanel })
+  vipWindow:hide()
+  TopMenu.addGameButton('vipListButton', 'VIP list', '/core_styles/icons/viplist.png', VipList.toggle)
 end
 
 function VipList.destroy()
@@ -43,21 +45,21 @@ function VipList.onAddVip(id, name, online)
   end
 
   label.vipOnline = online
-  
+
   local nameLower = name:lower()
   local childrenCount = vipList:getChildCount()
-  
+
   for i=1,childrenCount do
     local child = vipList:getChildByIndex(i)
     if online and not child.vipOnline then
       vipList:insertChild(i, label)
       return
     end
-    
+
     if (not online and not child.vipOnline) or (online and child.vipOnline) then
       local childText = child:getText():lower()
       local length = math.min(childText:len(), nameLower:len())
-      
+
       for j=1,length do
         if nameLower:byte(j) < childText:byte(j) then
           vipList:insertChild(i, label)
@@ -68,7 +70,7 @@ function VipList.onAddVip(id, name, online)
       end
     end
   end
-  
+
   vipList:insertChild(childrenCount+1, label)
 end
 
@@ -77,7 +79,7 @@ function VipList.onVipStateChange(id, online)
   local label = vipList:getChildById('vip' .. id)
   local text = label:getText()
   vipList:removeChild(label)
-  
+
   VipList.onAddVip(id, text, online)
 end
 
@@ -89,7 +91,7 @@ function VipList.onVipListMousePress(widget, mousePos, mouseButton)
   local menu = createWidget('PopupMenu')
   menu:addOption('Add new VIP', function() VipList.createAddWindow() end)
   menu:display(mousePos)
-  
+
   return true
 end
 
@@ -104,7 +106,7 @@ function VipList.onVipListLabelMousePress(widget, mousePos, mouseButton)
   menu:addSeparator()
   menu:addOption('Copy Name', function() g_window.setClipboardText(widget:getText()) end)
   menu:display(mousePos)
-  
+
   return true
 end
 
diff --git a/src/framework/core/configmanager.cpp b/src/framework/core/configmanager.cpp
index 410c1851..a88a6365 100644
--- a/src/framework/core/configmanager.cpp
+++ b/src/framework/core/configmanager.cpp
@@ -27,6 +27,11 @@
 
 ConfigManager g_configs;
 
+ConfigManager::ConfigManager()
+{
+    m_confsDoc = OTMLDocument::create();
+}
+
 bool ConfigManager::load(const std::string& file)
 {
     m_fileName = file;
@@ -35,9 +40,9 @@ bool ConfigManager::load(const std::string& file)
         return false;
 
     try {
-        OTMLDocumentPtr doc = OTMLDocument::parse(file);
-        for(const OTMLNodePtr& child : doc->children())
-            m_confsMap[child->tag()] = child->value();
+        OTMLDocumentPtr confsDoc = OTMLDocument::parse(file);
+        if(confsDoc)
+            m_confsDoc = confsDoc;
         return true;
     } catch(Exception& e) {
         logError("could not load configurations: ", e.what());
@@ -47,13 +52,65 @@ bool ConfigManager::load(const std::string& file)
 
 bool ConfigManager::save()
 {
-    OTMLDocumentPtr doc = OTMLDocument::create();
-    for(auto it : m_confsMap) {
-        if(it.second == "")
-            continue;
-        OTMLNodePtr node = OTMLNode::create(it.first, it.second);
-        doc->addChild(node);
-    }
-    return doc->save(m_fileName);
+    if(m_fileName.length() == 0)
+        return false;
+    return m_confsDoc->save(m_fileName);
 }
 
+void ConfigManager::set(const std::string& key, const std::string& value)
+{
+    if(key == "") {
+        remove(key);
+        return;
+    }
+
+    OTMLNodePtr child = OTMLNode::create(key, value);
+    m_confsDoc->addChild(child);
+}
+
+void ConfigManager::setList(const std::string& key, const std::vector<std::string>& list)
+{
+    remove(key);
+
+    if(list.size() == 0)
+        return;
+
+    OTMLNodePtr child = OTMLNode::create(key, true);
+    for(const std::string& value : list) {
+        child->writeIn(value);
+        dump << "insert" << value;
+    }
+    m_confsDoc->addChild(child);
+}
+
+bool ConfigManager::exists(const std::string& key)
+{
+    return m_confsDoc->hasChildAt(key);
+}
+
+std::string ConfigManager::get(const std::string& key)
+{
+    OTMLNodePtr child = m_confsDoc->get(key);
+    if(child)
+        return child->value();
+    else
+        return "";
+}
+
+std::vector<std::string> ConfigManager::getList(const std::string& key)
+{
+    std::vector<std::string> list;
+    OTMLNodePtr child = m_confsDoc->get(key);
+    if(child) {
+        for(const OTMLNodePtr& subchild : child->children())
+            list.push_back(subchild->value());
+    }
+    return list;
+}
+
+void ConfigManager::remove(const std::string& key)
+{
+    OTMLNodePtr child = m_confsDoc->get(key);
+    if(child)
+        m_confsDoc->removeChild(child);
+}
diff --git a/src/framework/core/configmanager.h b/src/framework/core/configmanager.h
index 8297b5f2..575836eb 100644
--- a/src/framework/core/configmanager.h
+++ b/src/framework/core/configmanager.h
@@ -24,21 +24,25 @@
 #define CONFIGMANAGER_H
 
 #include "declarations.h"
+#include <framework/otml/declarations.h>
 
 class ConfigManager
 {
 public:
+    ConfigManager();
     bool load(const std::string& file);
     bool save();
 
-    bool exists(const std::string& key) { return m_confsMap.find(key) != m_confsMap.end(); }
-    void set(const std::string& key, const std::string& value) { m_confsMap[key] = value; }
-    std::string get(const std::string& key) { return m_confsMap[key]; }
-    void remove(const std::string& key) { m_confsMap[key] = ""; }
+    void set(const std::string& key, const std::string& value);
+    void setList(const std::string& key, const std::vector<std::string>& list);
+    std::string get(const std::string& key);
+    std::vector<std::string> getList(const std::string& key);
+    bool exists(const std::string& key);
+    void remove(const std::string& key);
 
 private:
     std::string m_fileName;
-    std::map<std::string, std::string> m_confsMap;
+    OTMLDocumentPtr m_confsDoc;
 };
 
 extern ConfigManager g_configs;
diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp
index d1864bc6..a9daa038 100644
--- a/src/framework/luafunctions.cpp
+++ b/src/framework/luafunctions.cpp
@@ -366,7 +366,9 @@ void Application::registerLuaFunctions()
     // ConfigManager
     g_lua.registerStaticClass("g_configs");
     g_lua.bindClassStaticFunction("g_configs", "set", std::bind(&ConfigManager::set, &g_configs, _1, _2));
+    g_lua.bindClassStaticFunction("g_configs", "setList", std::bind(&ConfigManager::setList, &g_configs, _1, _2));
     g_lua.bindClassStaticFunction("g_configs", "get", std::bind(&ConfigManager::get, &g_configs, _1));
+    g_lua.bindClassStaticFunction("g_configs", "getList", std::bind(&ConfigManager::getList, &g_configs, _1));
     g_lua.bindClassStaticFunction("g_configs", "exists", std::bind(&ConfigManager::exists, &g_configs, _1));
     g_lua.bindClassStaticFunction("g_configs", "remove", std::bind(&ConfigManager::remove, &g_configs, _1));
 
diff --git a/src/framework/luascript/luavaluecasts.h b/src/framework/luascript/luavaluecasts.h
index da0cb0c8..a45d2137 100644
--- a/src/framework/luascript/luavaluecasts.h
+++ b/src/framework/luascript/luavaluecasts.h
@@ -125,6 +125,9 @@ luavalue_cast(int index, std::function<Ret(Args...)>& func);
 template<typename T>
 void push_luavalue(const std::vector<T>& vec);
 
+template<typename T>
+bool luavalue_cast(int index, std::vector<T>& vec);
+
 // deque
 template<class T>
 void push_luavalue(const std::deque<T>& vec);
@@ -249,6 +252,22 @@ void push_luavalue(const std::vector<T>& vec) {
     }
 }
 
+template<typename T>
+bool luavalue_cast(int index, std::vector<T>& vec)
+{
+    if(g_lua.isTable(index)) {
+        g_lua.pushNil();
+        while(g_lua.next(index < 0 ? index-1 : index)) {
+            T value;
+            if(luavalue_cast(-1, value))
+                vec.push_back(value);
+            g_lua.pop();
+        }
+        return true;
+    }
+    return false;
+}
+
 template<typename T>
 void push_luavalue(const std::deque<T>& vec) {
     g_lua.newTable();