From 239f58296e6ee399fa8b009edfbaf9280268b655 Mon Sep 17 00:00:00 2001
From: Eduardo Bart <edub4rt@gmail.com>
Date: Fri, 23 Mar 2012 10:48:05 -0300
Subject: [PATCH] restore inventory and healthbar

* make inventory/healthbar work again allowing reload
* changes in top menu toggle buttons
* all modules are now reloadable by default
* fix warning when using fade in
* remove some unused files
---
 modules/client/client.otmod                   |   1 +
 modules/client_about/about.otmod              |   1 -
 modules/client_background/background.lua      |   1 +
 modules/client_background/background.otmod    |   1 -
 modules/client_entergame/entergame.otmod      |   1 -
 .../client_modulemanager/modulemanager.otmod  |   3 -
 modules/client_options/options.otmod          |   1 -
 modules/client_terminal/terminal.otmod        |   1 -
 modules/client_topmenu/topmenu.lua            |  11 +-
 modules/client_topmenu/topmenu.otmod          |   1 -
 modules/client_topmenu/topmenu.otui           |   5 +-
 modules/core_lib/core_lib.otmod               |   1 +
 modules/core_lib/ui/effects.lua               |  44 ++--
 modules/core_styles/core_styles.otmod         |   1 +
 modules/game/game.otmod                       |  11 +-
 modules/game/gameinterface.lua                |   6 +-
 modules/game/gameinterface.otui               |   4 +-
 modules/{old => }/game/player.lua             |   0
 modules/game/styles/miniwindow.otui           |   3 +
 modules/game/widgets/uiitem.lua               |   2 +-
 modules/game_console/console.lua              |   7 +-
 modules/game_console/console.otmod            |   1 -
 modules/game_healthbar/healthbar.lua          |  22 +-
 modules/game_healthbar/healthbar.otmod        |   7 +
 modules/game_healthbar/healthbar.otui         |   2 +-
 modules/game_interface/gameinterface.lua      | 199 ------------------
 modules/game_interface/gameinterface.otmod    |  20 --
 modules/game_interface/gameinterface.otui     |  46 ----
 modules/game_interface/uimap.lua              |  56 -----
 modules/game_inventory/inventory.lua          |  39 ++--
 modules/game_inventory/inventory.otmod        |   8 +
 modules/game_inventory/inventory.otui         |   7 +-
 modules/game_outfit/outfit.otmod              |   1 -
 modules/game_skills/skills.lua                |   4 +-
 modules/game_skills/skills.otmod              |   4 +
 modules/game_textmessage/textmessage.otmod    |   1 -
 modules/game_tibiafiles/tibiafiles.otmod      |   1 +
 src/framework/core/module.cpp                 |   2 +-
 src/otclient/core/container.h                 |   4 +-
 src/otclient/core/player.h                    |   4 -
 src/otclient/luafunctions.cpp                 |   7 +-
 41 files changed, 134 insertions(+), 407 deletions(-)
 rename modules/{old => }/game/player.lua (100%)
 delete mode 100644 modules/game_interface/gameinterface.lua
 delete mode 100644 modules/game_interface/gameinterface.otmod
 delete mode 100644 modules/game_interface/gameinterface.otui
 delete mode 100644 modules/game_interface/uimap.lua

diff --git a/modules/client/client.otmod b/modules/client/client.otmod
index a3a8ea28..30f9501c 100644
--- a/modules/client/client.otmod
+++ b/modules/client/client.otmod
@@ -5,6 +5,7 @@ Module
   website: https://github.com/edubart/otclient
   autoload: true
   autoload-priority: 100
+  reloadable: false
 
   load-later:
     - client_topmenu
diff --git a/modules/client_about/about.otmod b/modules/client_about/about.otmod
index 0e98b90f..4aa758e2 100644
--- a/modules/client_about/about.otmod
+++ b/modules/client_about/about.otmod
@@ -3,7 +3,6 @@ Module
   description: Create the about window
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   dependencies:
     - client_topmenu
diff --git a/modules/client_background/background.lua b/modules/client_background/background.lua
index 5161fddb..7b31b3c2 100644
--- a/modules/client_background/background.lua
+++ b/modules/client_background/background.lua
@@ -25,6 +25,7 @@ function Background.terminate()
   disconnect(g_game, { onGameStart = Background.hide })
   disconnect(g_game, { onGameEnd = Background.show })
 
+  Effects.cancelFade(background:getChildById('clientVersionLabel'))
   background:destroy()
   background = nil
 
diff --git a/modules/client_background/background.otmod b/modules/client_background/background.otmod
index 312fca2b..a176c9cc 100644
--- a/modules/client_background/background.otmod
+++ b/modules/client_background/background.otmod
@@ -3,7 +3,6 @@ Module
   description: Handles the background of the login screen
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   dependencies:
     - client_topmenu
diff --git a/modules/client_entergame/entergame.otmod b/modules/client_entergame/entergame.otmod
index fc259753..8617200d 100644
--- a/modules/client_entergame/entergame.otmod
+++ b/modules/client_entergame/entergame.otmod
@@ -3,7 +3,6 @@ Module
   description: Manages enter game and character list windows
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   dependencies:
     - client_topmenu
diff --git a/modules/client_modulemanager/modulemanager.otmod b/modules/client_modulemanager/modulemanager.otmod
index a3b5fd87..368208cd 100644
--- a/modules/client_modulemanager/modulemanager.otmod
+++ b/modules/client_modulemanager/modulemanager.otmod
@@ -3,9 +3,6 @@ Module
   description: Manage other modules
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
-  autoload: true
-  autoload-priority: 140
 
   dependencies:
     - client_topmenu
diff --git a/modules/client_options/options.otmod b/modules/client_options/options.otmod
index bc9c118f..474db4b9 100644
--- a/modules/client_options/options.otmod
+++ b/modules/client_options/options.otmod
@@ -3,7 +3,6 @@ Module
   description: Create the options window
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   dependencies:
     - client_topmenu
diff --git a/modules/client_terminal/terminal.otmod b/modules/client_terminal/terminal.otmod
index e354205c..c32b3dc3 100644
--- a/modules/client_terminal/terminal.otmod
+++ b/modules/client_terminal/terminal.otmod
@@ -3,7 +3,6 @@ Module
   description: Terminal for executing lua functions
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   @onLoad: |
     dofile 'terminal'
diff --git a/modules/client_topmenu/topmenu.lua b/modules/client_topmenu/topmenu.lua
index 5fa5576a..1492ab0f 100644
--- a/modules/client_topmenu/topmenu.lua
+++ b/modules/client_topmenu/topmenu.lua
@@ -19,12 +19,7 @@ local function addButton(id, description, icon, callback, panel, toggle)
   button:setId(id)
   button:setTooltip(description)
   button:setIcon(resolvepath(icon, 3))
-
-  if toggle then
-    button.onCheckChange = callback
-  else
-    button.onClick = callback
-  end
+  button.onClick = callback
   return button
 end
 
@@ -38,6 +33,10 @@ function TopMenu.init()
   leftButtonsPanel = topMenu:getChildById('leftButtonsPanel')
   rightButtonsPanel = topMenu:getChildById('rightButtonsPanel')
   gameButtonsPanel = topMenu:getChildById('gameButtonsPanel')
+
+  if g_game.isOnline() then
+    gameButtonsPanel:show()
+  end
 end
 
 function TopMenu.terminate()
diff --git a/modules/client_topmenu/topmenu.otmod b/modules/client_topmenu/topmenu.otmod
index 82e357b4..db76bcb6 100644
--- a/modules/client_topmenu/topmenu.otmod
+++ b/modules/client_topmenu/topmenu.otmod
@@ -3,7 +3,6 @@ Module
   description: Create the top menu
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   @onLoad: |
     dofile 'topmenu'
diff --git a/modules/client_topmenu/topmenu.otui b/modules/client_topmenu/topmenu.otui
index fe791a4d..c75b654f 100644
--- a/modules/client_topmenu/topmenu.otui
+++ b/modules/client_topmenu/topmenu.otui
@@ -17,7 +17,7 @@ TopButton < UIButton
     image-color: #ffffff44
     icon-color: #ffffff44
 
-TopToggleButton < UICheckBox
+TopToggleButton < UIButton
   size: 26 26
   image-source: images/top_game_button.png
   image-clip: 26 0 26 26
@@ -25,7 +25,7 @@ TopToggleButton < UICheckBox
   image-border: 3
   icon-color: #ffffffff
 
-  $checked:
+  $on:
     image-clip: 0 0 26 26
     image-color: #ffffffff
     icon-color: #ffffffff
@@ -62,6 +62,7 @@ TopPanel
     anchors.bottom: parent.bottom
     anchors.left: prev.right
     anchors.right: next.left
+    visible: false
 
   TopMenuButtonsPanel
     id: rightButtonsPanel
diff --git a/modules/core_lib/core_lib.otmod b/modules/core_lib/core_lib.otmod
index 12845952..cabea4f1 100644
--- a/modules/core_lib/core_lib.otmod
+++ b/modules/core_lib/core_lib.otmod
@@ -5,6 +5,7 @@ Module
   website: https://github.com/edubart/otclient
   autoload: true
   autoload-priority: 10
+  reloadable: false
 
   @onLoad: |
     dofile 'ext/table'
diff --git a/modules/core_lib/ui/effects.lua b/modules/core_lib/ui/effects.lua
index e43a4f1c..f2399da7 100644
--- a/modules/core_lib/ui/effects.lua
+++ b/modules/core_lib/ui/effects.lua
@@ -1,26 +1,34 @@
 Effects = {}
 
 function Effects.fadeIn(widget, time, elapsed)
-    if not elapsed then elapsed = 0 end
-    if not time then time = 250 end
-    widget:setOpacity(math.min(elapsed/time, 1))
-    if elapsed < time then
-        scheduleEvent(function()
-                        Effects.fadeIn(widget, time, elapsed + 30)
-                      end, 30)
-    end
+  if not elapsed then elapsed = 0 end
+  if not time then time = 250 end
+  widget:setOpacity(math.min(elapsed/time, 1))
+  if elapsed < time then
+    removeEvent(widget.fadeEvent)
+    widget.fadeEvent = scheduleEvent(function()
+      Effects.fadeIn(widget, time, elapsed + 30)
+    end, 30)
+  else
+    widget.fadeEvent = nil
+  end
 end
 
 function Effects.fadeOut(widget, time, elapsed)
-    if not elapsed then elapsed = 0 end
-    if not time then time = 250 end
-    widget:setOpacity(math.max((time - elapsed)/time, 0))
-    if elapsed < time then
-        scheduleEvent(function()
-                        Effects.fadeOut(widget, time, elapsed + 30)
-                      end, 30)
-    else
-        widget:destroy()
-    end
+  if not elapsed then elapsed = 0 end
+  if not time then time = 250 end
+  widget:setOpacity(math.max((time - elapsed)/time, 0))
+  if elapsed < time then
+    removeEvent(widget.fadeEvent)
+    widget.fadeEvent = scheduleEvent(function()
+      Effects.fadeOut(widget, time, elapsed + 30)
+    end, 30)
+  else
+    widget.fadeEvent = nil
+    widget:destroy()
+  end
 end
 
+function Effects.cancelFade(widget)
+  removeEvent(widget.fadeEvent)
+end
diff --git a/modules/core_styles/core_styles.otmod b/modules/core_styles/core_styles.otmod
index b27e4d91..19755499 100644
--- a/modules/core_styles/core_styles.otmod
+++ b/modules/core_styles/core_styles.otmod
@@ -5,6 +5,7 @@ Module
   website: https://github.com/edubart/otclient
   autoload: true
   autoload-priority: 20
+  reloadable: false
 
   @onLoad: |
     importFont 'fonts/verdana-11px-antialised'
diff --git a/modules/game/game.otmod b/modules/game/game.otmod
index 79c3d20a..53d26ae4 100644
--- a/modules/game/game.otmod
+++ b/modules/game/game.otmod
@@ -3,7 +3,6 @@ Module
   description: Create the game interface, where the ingame stuff starts
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   dependencies:
     - game_tibiafiles
@@ -14,8 +13,8 @@ Module
     - game_textmessage
     - game_console
     - game_outfit
-    //- game_healthbar
-    //- game_inventory
+    - game_healthbar
+    - game_inventory
     //- game_combatcontrols
     //- game_skills
     //- game_viplist
@@ -30,9 +29,13 @@ Module
     dofile 'const'
 
     dofile 'widgets/uigamemap'
+    dofile 'widgets/uiitem'
+
+    dofile 'creature'
+    dofile 'player'
 
     dofile 'gameinterface'
-    dofile 'creature'
+
     GameInterface.init()
 
   @onUnload: |
diff --git a/modules/game/gameinterface.lua b/modules/game/gameinterface.lua
index 59e45eeb..3cd52550 100644
--- a/modules/game/gameinterface.lua
+++ b/modules/game/gameinterface.lua
@@ -105,7 +105,7 @@ function GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatu
 
   if useThing then
     if useThing:isContainer() then
-      if useThing:isInsideContainer() then
+      if useThing:getParentContainer() then
         menu:addOption('Open', function() g_game.open(useThing, useThing:getContainerId()) end)
         menu:addOption('Open in new window', function() g_game.open(useThing, Containers.getFreeContainerId()) end)
       else
@@ -220,7 +220,7 @@ function GameInterface.processMouseAction(menuPosition, mouseButton, autoWalk, l
       return true
     elseif useThing and keyboardModifiers == KeyboardCtrlModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
       if useThing:isContainer() then
-        if useThing:isInsideContainer() then
+        if useThing:getParentContainer() then
           g_game.open(useThing, useThing:getContainerId())
           return true
         else
@@ -245,7 +245,7 @@ function GameInterface.processMouseAction(menuPosition, mouseButton, autoWalk, l
         g_game.attack(multiUseThing:asCreature())
         return true
       elseif multiUseThing:isContainer() then
-        if multiUseThing:isInsideContainer() then
+        if multiUseThing:getParentContainer() then
           g_game.open(multiUseThing, multiUseThing:getContainerId())
           return true
         else
diff --git a/modules/game/gameinterface.otui b/modules/game/gameinterface.otui
index 5e44e293..3181e65a 100644
--- a/modules/game/gameinterface.otui
+++ b/modules/game/gameinterface.otui
@@ -33,8 +33,8 @@ UIWidget
     margin-bottom: 172
     height: 4
     margin-top: -2
-    background: red
     @canUpdateMargin: function(self, newMargin) return math.min(math.max(newMargin, 100), self:getParent():getHeight() - 300) end
+    @onGeometryChange: function(self) self:setMarginBottom(math.min(self:getParent():getHeight() - 300, self:getMarginBottom())) end
 
   GameBottomPanel
     id: gameBottomPanel
@@ -50,6 +50,7 @@ UIWidget
     anchors.right: parent.right
     anchors.top: parent.top
     anchors.bottom: parent.bottom
+    focusable: false
 
   GameSidePanel
     id: gameLeftPanel
@@ -58,6 +59,7 @@ UIWidget
     anchors.left: parent.left
     anchors.top: parent.top
     anchors.bottom: parent.bottom
+    focusable: false
 
   UIWidget
     id: mouseGrabber
diff --git a/modules/old/game/player.lua b/modules/game/player.lua
similarity index 100%
rename from modules/old/game/player.lua
rename to modules/game/player.lua
diff --git a/modules/game/styles/miniwindow.otui b/modules/game/styles/miniwindow.otui
index 8729dae7..b9d042b2 100644
--- a/modules/game/styles/miniwindow.otui
+++ b/modules/game/styles/miniwindow.otui
@@ -18,3 +18,6 @@ MiniWindow < UIMiniWindow
   $on:
     height: 24
     image-border-bottom: 1
+
+BorderlessGameWindow < UIWindow
+  focusable: false
\ No newline at end of file
diff --git a/modules/game/widgets/uiitem.lua b/modules/game/widgets/uiitem.lua
index 481f1d43..4f2b1249 100644
--- a/modules/game/widgets/uiitem.lua
+++ b/modules/game/widgets/uiitem.lua
@@ -73,6 +73,6 @@ function UIItem:onMouseRelease(mousePosition, mouseButton)
 
   local item = self:getItem()
   if not item or not self:containsPoint(mousePosition) then return false end
-  return g_game.processMouseAction(mousePosition, mouseButton, nil, item, item, nil, item)
+  return GameInterface.processMouseAction(mousePosition, mouseButton, nil, item, item, nil, item)
 end
 
diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua
index ff2acdf1..461a7d1f 100644
--- a/modules/game_console/console.lua
+++ b/modules/game_console/console.lua
@@ -155,7 +155,7 @@ function Console.init()
                     onChannelList = onChannelList,
                     onOpenChannel = onOpenChannel,
                     onOpenPrivateChannel = onOpenPrivateChannel,
-                    onGameEnd = Console.clean })
+                    onGameEnd = Console.clear })
 
   consolePanel = displayUI('console.otui', GameInterface.getBottomPanel())
   consoleLineEdit = consolePanel:getChildById('consoleLineEdit')
@@ -188,7 +188,7 @@ function Console.terminate()
                        onChannelList = onChannelList,
                        onOpenChannel = onOpenChannel,
                        onOpenPrivateChannel = onOpenPrivateChannel,
-                       onGameEnd = Console.clean })
+                       onGameEnd = Console.clear })
 
   for channelid, channelname in pairs(channels) do
     if channelid ~= 0 then
@@ -218,7 +218,7 @@ function Console.debug()
   print(#channels)
 end
 
-function Console.clean()
+function Console.clear()
   for channelid, channelname in pairs(channels) do
     if channelid ~= 0 then
       local tab = consoleTabBar:getTab(channelname)
@@ -229,6 +229,7 @@ function Console.clean()
 
   consoleTabBar:getTab('Default').tabPanel:destroyChildren()
   consoleTabBar:getTab('Server Log').tabPanel:destroyChildren()
+  consoleLineEdit:clearText()
 
   if channelsWindow then
     channelsWindow:destroy()
diff --git a/modules/game_console/console.otmod b/modules/game_console/console.otmod
index 09cb1d28..3d9a1b71 100644
--- a/modules/game_console/console.otmod
+++ b/modules/game_console/console.otmod
@@ -3,7 +3,6 @@ Module
   description: Manage chat window
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   dependecies:
     - game
diff --git a/modules/game_healthbar/healthbar.lua b/modules/game_healthbar/healthbar.lua
index a4678bcb..99b8cefc 100644
--- a/modules/game_healthbar/healthbar.lua
+++ b/modules/game_healthbar/healthbar.lua
@@ -8,17 +8,29 @@ local healthLabel
 local manaLabel
 
 -- public functions
-function HealthBar.create()
+function HealthBar.init()
+  connect(LocalPlayer, { onHealthChange = HealthBar.onHealthChange,
+                         onManaChange = HealthBar.onManaChange })
+
   healthBarWindow = displayUI('healthbar.otui', GameInterface.getRightPanel())
-  healthBarButton = TopMenu.addGameButton('healthBarButton', 'Healh Bar', 'healthbar.png', HealthBar.toggle)
+  healthBarButton = TopMenu.addGameToggleButton('healthBarButton', 'Healh Bar', 'healthbar.png', HealthBar.toggle)
   healthBarButton:setOn(true)
   healthBar = healthBarWindow:getChildById('healthBar')
   manaBar = healthBarWindow:getChildById('manaBar')
   healthLabel = healthBarWindow:getChildById('healthLabel')
   manaLabel = healthBarWindow:getChildById('manaLabel')
+
+  if g_game.isOnline() then
+    local localPlayer = g_game.getLocalPlayer()
+    HealthBar.onHealthChange(localPlayer, localPlayer:getHealth(), localPlayer:getMaxHealth())
+    HealthBar.onManaChange(localPlayer, localPlayer:getMana(), localPlayer:getMaxMana())
+  end
 end
 
-function HealthBar.destroy()
+function HealthBar.terminate()
+  disconnect(LocalPlayer, { onHealthChange = HealthBar.onHealthChange,
+                            onManaChange = HealthBar.onManaChange })
+
   healthBarWindow:destroy()
   healthBarWindow = nil
   healthBarButton:destroy()
@@ -53,7 +65,3 @@ function HealthBar.onManaChange(localPlayer, mana, maxMana)
   manaBar:setPercent(percent)
 end
 
-connect(g_game, { onGameStart = HealthBar.create,
-                onGameEnd = HealthBar.destroy })
-connect(LocalPlayer, { onHealthChange = HealthBar.onHealthChange,
-                       onManaChange = HealthBar.onManaChange })
diff --git a/modules/game_healthbar/healthbar.otmod b/modules/game_healthbar/healthbar.otmod
index 9df387c0..a358f276 100644
--- a/modules/game_healthbar/healthbar.otmod
+++ b/modules/game_healthbar/healthbar.otmod
@@ -4,5 +4,12 @@ Module
   author: OTClient team
   website: https://github.com/edubart/otclient
 
+  dependecies:
+    - game
+
   @onLoad: |
     dofile 'healthbar'
+    HealthBar.init()
+
+  @onUnload: |
+    HealthBar.terminate()
diff --git a/modules/game_healthbar/healthbar.otui b/modules/game_healthbar/healthbar.otui
index f80d571b..dda120fe 100644
--- a/modules/game_healthbar/healthbar.otui
+++ b/modules/game_healthbar/healthbar.otui
@@ -32,7 +32,7 @@ ManaLabel < GameLabel
   margin-top: 2
   text: 0 / 0
 
-UIWindow
+BorderlessGameWindow
   id: healthManaPanel
   width: 192
   height: 34
diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua
deleted file mode 100644
index a7a38a50..00000000
--- a/modules/game_interface/gameinterface.lua
+++ /dev/null
@@ -1,199 +0,0 @@
-GameInterface = {}
-
--- private variables
-local WALK_AUTO_REPEAT_DELAY = 90
-local gameRootPanel
-local gameMapPanel
-local gameRightPanel
-local gameLeftPanel
-local gameBottomPanel
-
--- private functions
-function onGameStart()
-  -- hook window close event
-  setonclose(GameInterface.tryLogout)
-  GameInterface.show()
-end
-
-function onGameEnd()
-  setonclose(exit)
-  GameInterface.hide()
-end
-
--- public functions
-function GameInterface.init()
-  gameRootPanel = displayUI('gameinterface.otui')
-  gameRootPanel:lower()
-  connect(g_game, { onGameStart = onGameStart }, true)
-  connect(g_game, { onGameEnd = onGameEnd })
-
-  Keyboard.bindKeyPress('Up', function() g_game.walk(North) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Right', function() g_game.walk(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Down', function() g_game.walk(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Left', function() g_game.walk(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Numpad8', function() g_game.walk(North) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Numpad9', function() g_game.walk(NorthEast) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Numpad6', function() g_game.walk(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Numpad3', function() g_game.walk(SouthEast) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Numpad2', function() g_game.walk(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Numpad1', function() g_game.walk(SouthWest) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Numpad4', function() g_game.walk(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Numpad7', function() g_game.walk(NorthWest) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Ctrl+Up', function() g_game.turn(North) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Ctrl+Right', function() g_game.turn(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Ctrl+Down', function() g_game.turn(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Ctrl+Left', function() g_game.turn(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Ctrl+Numpad8', function() g_game.turn(North) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Ctrl+Numpad6', function() g_game.turn(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Ctrl+Numpad2', function() g_game.turn(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Ctrl+Numpad4', function() g_game.turn(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-  Keyboard.bindKeyPress('Esc', function() g_game.cancelAttackAndFollow() end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
-end
-
-function GameInterface.terminate()
-  disconnect(g_game, { onGameStart = onGameStart }, true)
-  disconnect(g_game, { onGameEnd = onGameEnd })
-end
-
-function GameInterface.show()
-  gameRootPanel:show()
-end
-
-function GameInterface.hide()
-  gameRootPanel:hide()
-end
-
-function GameInterface.tryLogout()
-  if g_game.isOnline() then
-    g_game.forceLogout()
-  else
-    exit()
-  end
-end
-
-function GameInterface.getRootPanel()
-  return gameRootPanel
-end
-
-function GameInterface.getMapPanel()
-  return gameMapPanel
-end
-
-function GameInterface.getRightPanel()
-  return gameRightPanel
-end
-
-function GameInterface.getLeftPanel()
-  return gameLeftPanel
-end
-
-function GameInterface.getBottomPanel()
-  return gameBottomPanel
-end
-
-function GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatureThing)
-  local menu = createWidget('PopupMenu')
-
-  if lookThing then
-    menu:addOption('Look', function() g_game.look(lookThing) end)
-  end
-
-  if useThing then
-    if useThing:isContainer() then
-      if useThing:isInsideContainer() then
-        menu:addOption('Open', function() g_game.open(useThing, useThing:getContainerId()) end)
-        menu:addOption('Open in new window', function() g_game.open(useThing, Containers.getFreeContainerId()) end)
-      else
-        menu:addOption('Open', function() g_game.open(useThing, Containers.getFreeContainerId()) end)
-      end
-    else
-      if useThing:isMultiUse() then
-        menu:addOption('Use with ...', function() g_game.startUseWith(useThing) end)
-      else
-        menu:addOption('Use', function() g_game.use(useThing) end)
-      end
-    end
-
-    if useThing:isRotateable() then
-      menu:addOption('Rotate', function() g_game.rotate(useThing) end)
-    end
-
-  end
-
-  if lookThing and not lookThing:asCreature() and not lookThing:isNotMoveable() and lookThing:isPickupable() then
-    menu:addSeparator()
-    menu:addOption('Trade with ...', function() print('trade with') end)
-  end
-
-  -- check for move up
-
-  if creatureThing then
-    menu:addSeparator()
-
-    if creatureThing:asLocalPlayer() then
-      menu:addOption('Set Outfit', function() g_game.requestOutfit() end)
-
-      if creatureThing:asPlayer():isPartyMember() --[[and not fighting]] then
-        if creatureThing:asPlayer():isPartyLeader() then
-          if creatureThing:asPlayer():isPartySharedExperienceActive() then
-            menu:addOption('Disable Shared Experience', function() g_game.partyShareExperience(false) end)
-          else
-            menu:addOption('Enable Shared Experience', function() g_game.partyShareExperience(true) end)
-          end
-        end
-        menu:addOption('Leave Party', function() g_game.partyLeave() end)
-      end
-
-    else
-      local localPlayer = g_game.getLocalPlayer()
-      if localPlayer then
-        if g_game.getAttackingCreature() ~= creatureThing then
-          menu:addOption('Attack', function() g_game.attack(creatureThing) end)
-        else
-          menu:addOption('Stop Attack', function() g_game.cancelAttack() end)
-        end
-
-        if g_game.getFollowingCreature() ~= creatureThing then
-          menu:addOption('Follow', function() g_game.follow(creatureThing) end)
-        else
-          menu:addOption('Stop Follow', function() g_game.cancelFollow() end)
-        end
-
-        if creatureThing:asPlayer() then
-          menu:addSeparator()
-          menu:addOption('Message to ' .. creatureThing:getName(), function() print('message') end)
-          menu:addOption('Add to VIP list', function() g_game.addVip(creatureThing:getName()) end)
-
-          local localPlayerShield = localPlayer:asCreature():getShield()
-          local creatureShield = creatureThing:getShield()
-
-          if localPlayerShield == ShieldNone or localPlayerShield == ShieldWhiteBlue then
-            if creatureShield == ShieldWhiteYellow then
-              menu:addOption('Join ' .. creatureThing:getName() .. '\'s Party', function() g_game.partyJoin(creatureThing:getId()) end)
-            else
-              menu:addOption('Invite to Party', function() g_game.partyInvite(creatureThing:getId()) end)
-            end
-          elseif localPlayerShield == ShieldWhiteYellow then
-            if creatureShield == ShieldWhiteBlue then
-              menu:addOption('Revoke ' .. creatureThing:getName() .. '\'s Invitation', function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
-            end
-          elseif localPlayerShield == ShieldYellow or localPlayerShield == ShieldYellowSharedExp or localPlayerShield == ShieldYellowNoSharedExpBlink or localPlayerShield == ShieldYellowNoSharedExp then
-            if creatureShield == ShieldWhiteBlue then
-              menu:addOption('Revoke ' .. creatureThing:getName() .. '\'s Invitation', function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
-            elseif creatureShield == ShieldBlue or creatureShield == ShieldBlueSharedExp or creatureShield == ShieldBlueNoSharedExpBlink or creatureShield == ShieldBlueNoSharedExp then
-              menu:addOption('Pass Leadership to ' .. creatureThing:getName(), function() g_game.partyPassLeadership(creatureThing:getId()) end)
-            else
-              menu:addOption('Invite to Party', function() g_game.partyInvite(creatureThing:getId()) end)
-            end
-          end
-        end
-      end
-    end
-
-    menu:addSeparator()
-    menu:addOption('Copy Name', function() g_window.setClipboardText(creatureThing:getName()) end)
-
-  end
-
-  menu:display(menuPosition)
-end
diff --git a/modules/game_interface/gameinterface.otmod b/modules/game_interface/gameinterface.otmod
deleted file mode 100644
index 854b126f..00000000
--- a/modules/game_interface/gameinterface.otmod
+++ /dev/null
@@ -1,20 +0,0 @@
-Module
-  name: game_interface
-  description: |
-    Create the game main interface (map and bottom/left/right panels),
-    any game module must use it to add ingame interfaces
-
-  author: OTClient team
-  website: https://github.com/edubart/otclient
-
-  @onLoad: |
-    dofile 'uiminiwindow'
-    dofile 'uiminiwindowcontainer'
-    dofile 'uiitem'
-    dofile 'uimap'
-    dofile 'gameinterface'
-
-    GameInterface.init()
-
-  @onUnload: |
-    GameInterface.terminate()
diff --git a/modules/game_interface/gameinterface.otui b/modules/game_interface/gameinterface.otui
deleted file mode 100644
index 96b12a5f..00000000
--- a/modules/game_interface/gameinterface.otui
+++ /dev/null
@@ -1,46 +0,0 @@
-GameSidePanel < UIMiniWindowContainer
-  image-source: images/sidepanel.png
-  image-border: 4
-
-GameBottomPanel < Panel
-  image-source: images/bottompanel.png
-  image-border: 4
-
-GameMapPanel < UIMap
-  padding: 4
-  image-source: images/mappanel.png
-  image-border: 4
-
-UIGame
-  id: gameRootPanel
-  anchors.fill: parent
-  anchors.top: topMenu.bottom
-
-  GameSidePanel
-    id: gameRightPanel
-    width: 190
-    layout: verticalBox
-    anchors.right: parent.right
-    anchors.top: parent.top
-    anchors.bottom: parent.bottom
-
-  GameBottomPanel
-    id: gameBottomPanel
-    height: 170
-    anchors.left: parent.left
-    anchors.right: gameRightPanel.left
-    anchors.bottom: parent.bottom
-
-  GameMapPanel
-    id: gameMapPanel
-    anchors.left: parent.left
-    anchors.right: gameRightPanel.left
-    anchors.top: parent.top
-    anchors.bottom: gameBottomPanel.top
-    focusable: false
-
-  UIWidget
-    id: mouseGrabber
-    focusable: false
-    visible: false
-
diff --git a/modules/game_interface/uimap.lua b/modules/game_interface/uimap.lua
deleted file mode 100644
index bfc68e80..00000000
--- a/modules/game_interface/uimap.lua
+++ /dev/null
@@ -1,56 +0,0 @@
-function UIMap:onDragEnter(mousePos)
-  local tile = self:getTile(mousePos)
-  if not tile then return false end
-
-  local thing = tile:getTopMoveThing()
-  if not thing then return false end
-
-  self.parsed = false
-  self.currentDragThing = thing
-  Mouse.setTargetCursor()
-  return true
-end
-
-function UIMap:onDragLeave(droppedWidget, mousePos)
-  if not self.parsed then
-    self.currentDragThing = nil
-  end
-
-  Mouse.restoreCursor()
-  return true
-end
-
-function UIMap:onDrop(widget, mousePos)
-  if not widget or not widget.currentDragThing then return false end
-
-  local tile = self:getTile(mousePos)
-  if not tile then return false end
-
-  local count = widget.currentDragThing:getCount()
-  if widget.currentDragThing:isStackable() and count > 1 then
-    widget.parsed = true
-    local moveWindow = displayUI('/game/movewindow.otui')
-    local spinbox = moveWindow:getChildById('spinbox')
-    spinbox:setMaximum(count)
-    spinbox:setMinimum(1)
-    spinbox:setCurrentIndex(count)
-
-    local okButton = moveWindow:getChildById('buttonOk')
-    okButton.onClick = function()
-                         g_game.move(widget.currentDragThing, tile:getPosition(), spinbox:getCurrentIndex())
-                         okButton:getParent():destroy()
-                         widget.currentDragThing = nil
-                       end
-    moveWindow.onEnter = okButton.onClick
-  else
-    g_game.move(widget.currentDragThing, tile:getPosition(), 1)
-  end
-
-  return true
-end
-
-function UIMap:onMouseRelease(mousePosition, mouseButton)
-  local tile = self:getTile(mousePosition)
-  if tile and g_game.processMouseAction(mousePosition, mouseButton, nil, tile:getTopLookThing(), tile:getTopUseThing(), tile:getTopCreature(), tile:getTopMultiUseThing()) then return true end
-  return false
-end
diff --git a/modules/game_inventory/inventory.lua b/modules/game_inventory/inventory.lua
index 4631d346..168a96d0 100644
--- a/modules/game_inventory/inventory.lua
+++ b/modules/game_inventory/inventory.lua
@@ -5,15 +5,31 @@ local inventoryWindow
 local inventoryButton
 
 -- public functions
-function Inventory.create()
-  inventoryWindow = displayUI('inventory.otui', GameInterface.getRightPanel())
-  inventoryButton = TopMenu.addGameButton('inventoryButton', 'Inventory (Ctrl+I)', 'inventory.png', Inventory.toggle)
-  inventoryButton:setOn(true)
+function Inventory.init()
+  connect(g_game, { onGameEnd = Inventory.clear,
+                    onInventoryChange = Inventory.onInventoryChange,
+                    onFreeCapacityChange = Inventory.onFreeCapacityChange,
+                    onSoulChange = Inventory.onSoulChange })
+
   Keyboard.bindKeyDown('Ctrl+I', Inventory.toggle)
+
+  inventoryWindow = displayUI('inventory.otui', GameInterface.getRightPanel())
+  inventoryButton = TopMenu.addGameToggleButton('inventoryButton', 'Inventory (Ctrl+I)', 'inventory.png', Inventory.toggle)
+  inventoryButton:setOn(true)
+
+  if g_game.isOnline() then
+    Inventory.reload()
+  end
 end
 
-function Inventory.destroy()
+function Inventory.terminate()
+  connect(g_game, { onGameEnd = Inventory.clear,
+                    onInventoryChange = Inventory.onInventoryChange,
+                    onFreeCapacityChange = Inventory.onFreeCapacityChange,
+                    onSoulChange = Inventory.onSoulChange })
+
   Keyboard.unbindKeyDown('Ctrl+I')
+
   inventoryWindow:destroy()
   inventoryWindow = nil
   inventoryButton:destroy()
@@ -26,6 +42,12 @@ function Inventory.toggle()
   inventoryButton:setOn(visible)
 end
 
+function Inventory.clear()
+end
+
+function Inventory.reload()
+end
+
 -- hooked events
 function Inventory.onInventoryChange(slot, item)
   local itemWidget = inventoryWindow:getChildById('slot' .. slot)
@@ -41,10 +63,3 @@ function Inventory.onSoulChange(soul)
   local widget = inventoryWindow:getChildById('soul')
   widget:setText("Soul:\n" .. soul)
 end
-
-connect(g_game, { onGameStart = Inventory.create,
-                onGameEnd = Inventory.destroy,
-                onInventoryChange = Inventory.onInventoryChange,
-                onFreeCapacityChange = Inventory.onFreeCapacityChange,
-                onSoulChange = Inventory.onSoulChange })
-
diff --git a/modules/game_inventory/inventory.otmod b/modules/game_inventory/inventory.otmod
index 6e1aa54d..5256bb38 100644
--- a/modules/game_inventory/inventory.otmod
+++ b/modules/game_inventory/inventory.otmod
@@ -4,5 +4,13 @@ Module
   author: OTClient team
   website: https://github.com/edubart/otclient
 
+  dependecies:
+    - game
+
   @onLoad: |
     dofile 'inventory'
+    Inventory.init()
+
+  @onUnload: |
+    Inventory.terminate()
+
diff --git a/modules/game_inventory/inventory.otui b/modules/game_inventory/inventory.otui
index 5b0884a1..59125ffc 100644
--- a/modules/game_inventory/inventory.otui
+++ b/modules/game_inventory/inventory.otui
@@ -1,4 +1,5 @@
-UIWindow
+BorderlessGameWindow
+  id: inventoryWindow
   width: 192
   height: 154
   margin-top: 10
@@ -93,9 +94,7 @@ UIWindow
     anchors.left: slot9.left
     anchors.right: slot9.right
     margin-top: 5
-
     text-align: center
-
     image-source: /core_styles/styles/images/panel_flat.png
     image-border: 1
 
@@ -106,9 +105,7 @@ UIWindow
     anchors.left: slot10.left
     anchors.right: slot10.right
     margin-top: 5
-
     text-align: center
-
     image-source: /core_styles/styles/images/panel_flat.png
     image-border: 1
 
diff --git a/modules/game_outfit/outfit.otmod b/modules/game_outfit/outfit.otmod
index 2d1bf655..5119ad92 100644
--- a/modules/game_outfit/outfit.otmod
+++ b/modules/game_outfit/outfit.otmod
@@ -3,7 +3,6 @@ Module
   description: Change local player outfit
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   @onLoad: |
     dofile 'outfit'
diff --git a/modules/game_skills/skills.lua b/modules/game_skills/skills.lua
index 6df65ebb..a125f486 100644
--- a/modules/game_skills/skills.lua
+++ b/modules/game_skills/skills.lua
@@ -41,14 +41,14 @@ local function setSkillPercent(id, percent, tooltip)
 end
 
 -- public functions
-function Skills.create()
+function Skills.init()
   skillsWindow = displayUI('skills.otui', GameInterface.getRightPanel())
   skillsWindow:hide()
   skillsButton = TopMenu.addGameButton('skillsButton', 'Skills (Ctrl+S)', '/core_styles/icons/skills.png', Skills.toggle)
   Keyboard.bindKeyDown('Ctrl+S', Skills.toggle)
 end
 
-function Skills.destroy()
+function Skills.terminate()
   Keyboard.unbindKeyDown('Ctrl+S')
   skillsButton:destroy()
   skillsButton = nil
diff --git a/modules/game_skills/skills.otmod b/modules/game_skills/skills.otmod
index 991f6fc6..fc567318 100644
--- a/modules/game_skills/skills.otmod
+++ b/modules/game_skills/skills.otmod
@@ -6,3 +6,7 @@ Module
 
   @onLoad: |
     dofile 'skills'
+    Skills.init()
+
+  @onUnload: |
+    Skills.terminate()
diff --git a/modules/game_textmessage/textmessage.otmod b/modules/game_textmessage/textmessage.otmod
index 8ebf958f..a52bb11f 100644
--- a/modules/game_textmessage/textmessage.otmod
+++ b/modules/game_textmessage/textmessage.otmod
@@ -3,7 +3,6 @@ Module
   description: Manage game text messages
   author: OTClient team
   website: https://github.com/edubart/otclient
-  reloadable: true
 
   dependecies:
     - game
diff --git a/modules/game_tibiafiles/tibiafiles.otmod b/modules/game_tibiafiles/tibiafiles.otmod
index 1af149ad..7a62763c 100644
--- a/modules/game_tibiafiles/tibiafiles.otmod
+++ b/modules/game_tibiafiles/tibiafiles.otmod
@@ -1,6 +1,7 @@
 Module
   name: game_tibiafiles
   description: Contains tibia spr and dat
+  reloadable: false
 
   @onLoad: |
     if not g_thingsType.load('/game_tibiafiles/Tibia.dat') then
diff --git a/src/framework/core/module.cpp b/src/framework/core/module.cpp
index 8eb2fb34..a2ba3be0 100644
--- a/src/framework/core/module.cpp
+++ b/src/framework/core/module.cpp
@@ -108,7 +108,7 @@ void Module::discover(const OTMLNodePtr& moduleNode)
     m_website = moduleNode->valueAt("website", none);
     m_version = moduleNode->valueAt("version", none);
     m_autoLoad = moduleNode->valueAt<bool>("autoload", false);
-    m_reloadable = moduleNode->valueAt<bool>("reloadable", false);
+    m_reloadable = moduleNode->valueAt<bool>("reloadable", true);
     m_autoLoadPriority = moduleNode->valueAt<int>("autoload-priority", 9999);
 
     if(OTMLNodePtr node = moduleNode->get("dependencies")) {
diff --git a/src/otclient/core/container.h b/src/otclient/core/container.h
index f29a5b42..e8fc1010 100644
--- a/src/otclient/core/container.h
+++ b/src/otclient/core/container.h
@@ -25,7 +25,9 @@
 
 #include "declarations.h"
 
-class Container
+#include <framework/luascript/luaobject.h>
+
+class Container : public LuaObject
 {
 public:
     Container();
diff --git a/src/otclient/core/player.h b/src/otclient/core/player.h
index 83c93b1a..461c4069 100644
--- a/src/otclient/core/player.h
+++ b/src/otclient/core/player.h
@@ -31,10 +31,6 @@ public:
     Player() { }
     virtual ~Player() { }
 
-    bool isPartyMember() { return (m_shield != 0); }
-    bool isPartyLeader() { return (m_shield & Otc::ShieldYellow); } 
-    bool isPartySharedExperienceActive() { return false; }
-
     PlayerPtr asPlayer() { return std::static_pointer_cast<Player>(shared_from_this()); }
 };
 
diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp
index db80ce73..942a7533 100644
--- a/src/otclient/luafunctions.cpp
+++ b/src/otclient/luafunctions.cpp
@@ -25,6 +25,7 @@
 #include <otclient/luascript/luavaluecasts.h>
 #include <otclient/core/game.h>
 #include <otclient/core/tile.h>
+#include <otclient/core/container.h>
 #include <otclient/core/item.h>
 #include <otclient/core/effect.h>
 #include <otclient/core/missile.h>
@@ -161,6 +162,8 @@ void OTClient::registerLuaFunctions()
 
     g_lua.registerClass<ProtocolGame, Protocol>();
 
+    g_lua.registerClass<Container>();
+
     g_lua.registerClass<Thing>();
     g_lua.bindClassMemberFunction<Thing>("setId", &Thing::setId);
     g_lua.bindClassMemberFunction<Thing>("setPosition", &Thing::setPosition);
@@ -192,6 +195,7 @@ void OTClient::registerLuaFunctions()
     g_lua.bindClassMemberFunction<Thing>("isHookSouth", &Thing::isHookSouth);
     g_lua.bindClassMemberFunction<Thing>("isTranslucent", &Thing::isTranslucent);
     g_lua.bindClassMemberFunction<Thing>("isFullGround", &Thing::isFullGround);
+    g_lua.bindClassMemberFunction<Thing>("getParentContainer", &Thing::getParentContainer);
 
     g_lua.registerClass<Creature, Thing>();
     g_lua.bindClassMemberFunction<Creature>("getId", &Creature::getId);
@@ -221,9 +225,6 @@ void OTClient::registerLuaFunctions()
     g_lua.registerClass<AnimatedText, Thing>();
 
     g_lua.registerClass<Player, Creature>();
-    g_lua.bindClassMemberFunction<Player>("isPartyMember", &LocalPlayer::isPartyMember);
-    g_lua.bindClassMemberFunction<Player>("isPartyLeader", &LocalPlayer::isPartyLeader);
-    g_lua.bindClassMemberFunction<Player>("isPartySharedExperienceActive", &LocalPlayer::isPartySharedExperienceActive);
     g_lua.registerClass<Npc, Creature>();
     g_lua.registerClass<Monster, Creature>();