restore containers

* implemente Container class
* restore module containers
* add lua bindings for std::map
* improve grid layout
* fixes in UIItem rendering
* changes in miniwindow design
This commit is contained in:
Eduardo Bart 2012-04-02 20:09:47 -03:00
parent 231ba17ba1
commit 90d3acce2a
23 changed files with 428 additions and 178 deletions

View File

@ -17,8 +17,9 @@ Module
- game_skills - game_skills
- game_inventory - game_inventory
- game_combatcontrols - game_combatcontrols
- game_battle - game_containers
- game_viplist - game_viplist
- game_battle
- game_hotkeys - game_hotkeys
@onLoad: | @onLoad: |

View File

@ -140,10 +140,10 @@ function GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatu
if useThing then if useThing then
if useThing:isContainer() then if useThing:isContainer() then
if useThing:getParentContainer() then if useThing:getParentContainer() then
menu:addOption('Open', function() g_game.open(useThing, useThing:getContainerId()) end) menu:addOption('Open', function() g_game.open(useThing, useThing:getParentContainer()) end)
menu:addOption('Open in new window', function() g_game.open(useThing, Containers.getFreeContainerId()) end) menu:addOption('Open in new window', function() g_game.open(useThing, nil) end)
else else
menu:addOption('Open', function() g_game.open(useThing, Containers.getFreeContainerId()) end) menu:addOption('Open', function() g_game.open(useThing, nil) end)
end end
else else
if useThing:isMultiUse() then if useThing:isMultiUse() then
@ -256,10 +256,10 @@ function GameInterface.processMouseAction(menuPosition, mouseButton, autoWalk, l
elseif useThing and keyboardModifiers == KeyboardCtrlModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then elseif useThing and keyboardModifiers == KeyboardCtrlModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
if useThing:isContainer() then if useThing:isContainer() then
if useThing:getParentContainer() then if useThing:getParentContainer() then
g_game.open(useThing, useThing:getContainerId()) g_game.open(useThing, useThing:getParentContainer())
return true return true
else else
g_game.open(useThing, Containers.getFreeContainerId()) g_game.open(useThing, nil)
return true return true
end end
elseif useThing:isMultiUse() then elseif useThing:isMultiUse() then
@ -281,10 +281,10 @@ function GameInterface.processMouseAction(menuPosition, mouseButton, autoWalk, l
return true return true
elseif multiUseThing:isContainer() then elseif multiUseThing:isContainer() then
if multiUseThing:getParentContainer() then if multiUseThing:getParentContainer() then
g_game.open(multiUseThing, multiUseThing:getContainerId()) g_game.open(multiUseThing, multiUseThing:getParentContainer())
return true return true
else else
g_game.open(multiUseThing, Containers.getFreeContainerId()) g_game.open(multiUseThing, nil)
return true return true
end end
elseif multiUseThing:isMultiUse() then elseif multiUseThing:isMultiUse() then

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 758 B

View File

@ -1,5 +1,6 @@
Item < UIItem Item < UIItem
size: 34 34 size: 34 34
padding: 1
image-source: /core_styles/styles/images/item.png image-source: /core_styles/styles/images/item.png
font: verdana-11px-rounded font: verdana-11px-rounded
border-color: white border-color: white

View File

@ -3,7 +3,7 @@ MiniWindow < UIMiniWindow
icon-rect: 4 4 16 16 icon-rect: 4 4 16 16
width: 192 width: 192
height: 200 height: 200
text-offset: 26 5 text-offset: 24 5
text-align: topLeft text-align: topLeft
margin-bottom: 2 margin-bottom: 2
move-policy: free updated move-policy: free updated
@ -82,7 +82,7 @@ MiniWindowContents < ScrollablePanel
id: contentsPanel id: contentsPanel
anchors.fill: parent anchors.fill: parent
margin-right: 14 margin-right: 14
padding: 25 6 6 6 padding: 24 3 3 5
vertical-scrollbar: miniwindowScrollBar vertical-scrollbar: miniwindowScrollBar
BorderlessGameWindow < UIWindow BorderlessGameWindow < UIWindow

View File

@ -36,7 +36,7 @@ table.insert(lifeBarColors, {percentAbove = -1, color = '#4F0000' } )
-- public functions -- public functions
function Battle.init() function Battle.init()
battleWindow = displayUI('battle.otui', GameInterface.getRightPanel()) battleWindow = displayUI('battle.otui', GameInterface.getLeftPanel())
battleButton = TopMenu.addGameToggleButton('battleButton', 'Battle (Ctrl+B)', 'battle.png', Battle.toggle) battleButton = TopMenu.addGameToggleButton('battleButton', 'Battle (Ctrl+B)', 'battle.png', Battle.toggle)
battleButton:setOn(true) battleButton:setOn(true)
Keyboard.bindKeyDown('Ctrl+B', Battle.toggle) Keyboard.bindKeyDown('Ctrl+B', Battle.toggle)

View File

@ -1,11 +1,35 @@
MiniWindow ContainerWindow < MiniWindow
size: 200 221 height: 150
layout: UIItem
type: grid id: containerItemWidget
cell-size: 34 34 virtual: true
cell-spacing: 5 item-id: 3253
num-columns: 4 size: 32 32
num-lines: 5 anchors.top: parent.top
anchors.left: parent.left
margin-top: -6
margin-left: -6
UIButton
id: upButton
anchors.top: minimizeButton.top
anchors.right: minimizeButton.left
margin-right: 3
size: 14 14
image-source: /game/images/miniwindowbuttons.png
image-clip: 42 0 14 14
$hover:
image-clip: 42 14 14 14
$pressed:
image-clip: 42 28 14 14
MiniWindowContents
padding: 27 6 6 8
layout:
type: grid
cell-size: 34 34
flow: true
auto-spacing: true

View File

@ -1,138 +1,90 @@
Containers = {} Containers = {}
local function refreshContainerItems(container)
-- private variables for slot=0,container:getCapacity()-1 do
local containers = {} local itemWidget = container.itemsPanel:getChildById('item' .. slot)
itemWidget:setItem(container:getItem(slot))
-- public functions end
function Containers.clean()
containers = {}
end end
function Containers.getFreeContainerId() local function onContainerOpen(container, previousContainer)
for i=0,15 do local containerWindow
if not containers[i] then if previousContainer then
return i containerWindow = previousContainer.window
end previousContainer.window = nil
previousContainer.itemsPanel = nil
else
containerWindow = createWidget('ContainerWindow', GameInterface.getRightPanel())
end end
return 0 containerWindow:setId('container' .. container:getId())
end local containerPanel = containerWindow:getChildById('contentsPanel')
local containerItemWidget = containerWindow:getChildById('containerItemWidget')
-- hooked events containerWindow.onClose = function()
function Containers.onOpenContainer(containerId, itemId, name, capacity, hasParent, items) g_game.close(container)
local container = containers[containerId] containerWindow:hide()
if container then
GameInterface.getRightPanel():removeChild(container)
end end
container = displayUI('container.otui', GameInterface.getRightPanel()) local upButton = containerWindow:getChildById('upButton')
upButton.onClick = function()
g_game.openParent(container)
end
upButton:setVisible(container:hasParent())
local name = container:getName()
name = name:sub(1,1):upper() .. name:sub(2) name = name:sub(1,1):upper() .. name:sub(2)
container:setText(name) containerWindow:setText(name)
-- set icon, itemid containerItemWidget:setItemId(container:getItemId())
-- closebutton
-- resize containerPanel:destroyChildren()
if hasParent then for slot=0,container:getCapacity()-1 do
-- parent button local itemWidget = createWidget('Item', containerPanel)
itemWidget:setId('item' .. slot)
itemWidget:setItem(container:getItem(slot))
itemWidget.position = container:getSlotPosition(slot)
end end
container.itemCount = #items container.window = containerWindow
container.capacity = capacity container.itemsPanel = containerPanel
for i=1,capacity do
local itemWidget = UIItem.create()
itemWidget:setStyle('Item')
container:addChild(itemWidget)
itemWidget.position = {x=65535, y=containerId+64, z=i-1}
if i <= #items then
local item = items[i]
item:setPosition(itemWidget.position)
itemWidget:setItem(item)
end
end
containers[containerId] = container
end end
function Containers.onCloseContainer(containerId) local function onContainerClose(container)
local container = containers[containerId] local containerWindow = container.window
if container then if containerWindow then
GameInterface.getRightPanel():removeChild(container) containerWindow:destroy()
end end
containers[containerId] = nil
end end
function Containers.onContainerAddItem(containerId, item) local function onContainerAddItem(container, slot, item)
local container = containers[containerId] refreshContainerItems(container)
if not container or not item or container.itemCount >= container.capacity then return end end
local i = container.itemCount local function onContainerUpdateItem(container, slot, item, oldItem)
while i >= 1 do local itemWidget = container.itemsPanel:getChildById('item' .. slot)
local itemWidget = container:getChildByIndex(i)
if not itemWidget then return end
local nextItemWidget = container:getChildByIndex(i+1)
if not nextItemWidget then return end
local swapItem = itemWidget:getItem()
if swapItem then
swapItem:setPosition(nextItemWidget.position)
nextItemWidget:setItem(swapItem)
end
i = i - 1
end
local itemWidget = container:getChildByIndex(1)
if not itemWidget then return end
item:setPosition(itemWidget.position)
itemWidget:setItem(item) itemWidget:setItem(item)
container.itemCount = container.itemCount + 1
end end
function Containers.onContainerUpdateItem(containerId, slot, item) local function onContainerRemoveItem(container, slot, item)
local container = containers[containerId] refreshContainerItems(container)
if not container then return end
local itemWidget = container:getChildByIndex(slot + 1)
if not itemWidget then return end
itemWidget:setItem(item)
item:setPosition(itemWidget.position)
end end
function Containers.onContainerRemoveItem(containerId, slot) function Containers.init()
local container = containers[containerId] importStyle 'container.otui'
if not container then return end
local itemWidget = container:getChildByIndex(slot+1) connect(Container, { onOpen = onContainerOpen,
if not itemWidget then return end onClose = onContainerClose,
itemWidget:setItem(nil) onAddItem = onContainerAddItem,
onUpdateItem = onContainerUpdateItem,
for i=slot,container.itemCount-2 do onRemoveItem = onContainerRemoveItem })
local itemWidget = container:getChildByIndex(i+1)
if not itemWidget then return end
local nextItemWidget = container:getChildByIndex(i+2)
if not nextItemWidget then return end
local item = nextItemWidget:getItem()
local pos = item:getPosition()
pos.z = pos.z - 1
item:setPosition(pos)
itemWidget:setItem(item)
nextItemWidget:setItem(nil)
end
container.itemCount = container.itemCount - 1
end end
connect(g_game, { onGameStart = Containers.clean, function Containers.terminate()
onGameEnd = Containers.clean, disconnect(Container, { onOpen = onContainerOpen,
onOpenContainer = Containers.onOpenContainer, onClose = onContainerClose,
onCloseContainer = Containers.onCloseContainer, onAddItem = onContainerAddItem,
onContainerAddItem = Containers.onContainerAddItem, onUpdateItem = onContainerUpdateItem,
onContainerUpdateItem = Containers.onContainerUpdateItem, onRemoveItem = onContainerRemoveItem })
onContainerRemoveItem = Containers.onContainerRemoveItem }) end
function Containers.clean()
end

View File

@ -4,5 +4,12 @@ Module
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
dependecies:
- game
@onLoad: | @onLoad: |
dofile 'containers' dofile 'containers'
Containers.init()
@onUnload: |
Containers.terminate()

View File

@ -135,6 +135,13 @@ void push_luavalue(const std::deque<T>& vec);
template<typename T> template<typename T>
bool luavalue_cast(int index, std::deque<T>& vec); bool luavalue_cast(int index, std::deque<T>& vec);
// map
template<class K, class V>
void push_luavalue(const std::map<K, V>& map);
template<class K, class V>
bool luavalue_cast(int index, std::map<K, V>& map);
// tuple // tuple
template<typename... Args> template<typename... Args>
void push_luavalue(const std::tuple<Args...>& tuple); void push_luavalue(const std::tuple<Args...>& tuple);
@ -299,6 +306,34 @@ bool luavalue_cast(int index, std::deque<T>& vec)
return false; return false;
} }
template<class K, class V>
void push_luavalue(const std::map<K, V>& map)
{
g_lua.newTable();
for(auto& it : map) {
push_luavalue(it.first);
push_luavalue(it.second);
g_lua.rawSet();
}
}
template<class K, class V>
bool luavalue_cast(int index, std::map<K, V>& map)
{
if(g_lua.isTable(index)) {
g_lua.pushNil();
while(g_lua.next(index < 0 ? index-1 : index)) {
K key;
V value;
if(luavalue_cast(-1, value) && luavalue_cast(-2, key))
map[key] = value;
g_lua.pop();
}
return true;
}
return false;
}
template<int N> template<int N>
struct push_tuple_luavalue { struct push_tuple_luavalue {
template<typename Tuple> template<typename Tuple>

View File

@ -23,12 +23,14 @@
#include "uigridlayout.h" #include "uigridlayout.h"
#include "uiwidget.h" #include "uiwidget.h"
#include <framework/core/eventdispatcher.h>
UIGridLayout::UIGridLayout(UIWidgetPtr parentWidget): UILayout(parentWidget) UIGridLayout::UIGridLayout(UIWidgetPtr parentWidget): UILayout(parentWidget)
{ {
m_cellSize = Size(16,16); m_cellSize = Size(16,16);
m_cellSpacing = 0; m_cellSpacing = 0;
m_numColumns = 1; m_numColumns = 1;
m_numLines = 1; m_numLines = 0;
} }
void UIGridLayout::applyStyle(const OTMLNodePtr& styleNode) void UIGridLayout::applyStyle(const OTMLNodePtr& styleNode)
@ -49,6 +51,12 @@ void UIGridLayout::applyStyle(const OTMLNodePtr& styleNode)
setNumColumns(node->value<int>()); setNumColumns(node->value<int>());
else if(node->tag() == "num-lines") else if(node->tag() == "num-lines")
setNumLines(node->value<int>()); setNumLines(node->value<int>());
else if(node->tag() == "fit-children")
setFitChildren(node->value<bool>());
else if(node->tag() == "auto-spacing")
setAutoSpacing(node->value<bool>());
else if(node->tag() == "flow")
setFlow(node->value<bool>());
} }
} }
@ -71,24 +79,42 @@ bool UIGridLayout::internalUpdate()
Rect clippingRect = parentWidget->getClippingRect(); Rect clippingRect = parentWidget->getClippingRect();
Point topLeft = clippingRect.topLeft(); Point topLeft = clippingRect.topLeft();
int numColumns = m_numColumns;
if(m_flow && m_cellSize.width() > 0)
numColumns = clippingRect.width() / (m_cellSize.width() + m_cellSpacing);
int cellSpacing = m_cellSpacing;
if(m_autoSpacing && numColumns > 1)
cellSpacing = (clippingRect.width() - numColumns * m_cellSize.width()) / (numColumns - 1);
int index = 0; int index = 0;
int preferredHeight = 0;
for(const UIWidgetPtr& widget : widgets) { for(const UIWidgetPtr& widget : widgets) {
if(!widget->isExplicitlyVisible()) if(!widget->isExplicitlyVisible())
continue; continue;
int line = index / m_numColumns; int line = index / numColumns;
int column = index % m_numColumns; int column = index % numColumns;
Point virtualPos = Point(column * (m_cellSize.width() + m_cellSpacing), line * (m_cellSize.height() + m_cellSpacing)); Point virtualPos = Point(column * (m_cellSize.width() + cellSpacing), line * (m_cellSize.height() + cellSpacing));
Point pos = topLeft + virtualPos; preferredHeight = virtualPos.y + m_cellSize.height();
Point pos = topLeft + virtualPos - parentWidget->getVirtualOffset();
if(widget->setRect(Rect(pos, m_cellSize))) if(widget->setRect(Rect(pos, m_cellSize)))
changed = true; changed = true;
index++; index++;
if(index >= m_numColumns * m_numLines) if(m_numLines > 0 && index >= m_numColumns * m_numLines)
break; break;
} }
preferredHeight += parentWidget->getPaddingTop() + parentWidget->getPaddingBottom();
if(m_fitChildren && preferredHeight != parentWidget->getHeight()) {
// must set the preferred height later
g_eventDispatcher.addEvent([=] {
parentWidget->setHeight(preferredHeight);
});
}
return changed; return changed;
} }

View File

@ -40,6 +40,9 @@ public:
void setCellSpacing(int spacing) { m_cellSpacing = spacing; update(); } void setCellSpacing(int spacing) { m_cellSpacing = spacing; update(); }
void setNumColumns(int columns) { m_numColumns = columns; update(); } void setNumColumns(int columns) { m_numColumns = columns; update(); }
void setNumLines(int lines) { m_numLines = lines; update(); } void setNumLines(int lines) { m_numLines = lines; update(); }
void setAutoSpacing(bool enable) { m_autoSpacing = enable; update(); }
void setFitChildren(bool enable) { m_fitChildren = enable; update(); }
void setFlow(bool enable) { m_flow = enable; update(); }
virtual UIGridLayoutPtr asUIGridLayout() { return nullptr; } virtual UIGridLayoutPtr asUIGridLayout() { return nullptr; }
@ -51,6 +54,9 @@ private:
int m_cellSpacing; int m_cellSpacing;
int m_numColumns; int m_numColumns;
int m_numLines; int m_numLines;
Boolean<false> m_autoSpacing;
Boolean<false> m_fitChildren;
Boolean<false> m_flow;
}; };
#endif #endif

View File

@ -48,7 +48,7 @@ bool UIHorizontalLayout::internalUpdate()
bool changed = false; bool changed = false;
Rect clippingRect = parentWidget->getClippingRect(); Rect clippingRect = parentWidget->getClippingRect();
Point pos = (m_alignRight) ? clippingRect.topRight() : clippingRect.topLeft(); Point pos = (m_alignRight) ? clippingRect.topRight() : clippingRect.topLeft();
int prefferedWidth = 0; int preferredWidth = 0;
int gap; int gap;
for(const UIWidgetPtr& widget : widgets) { for(const UIWidgetPtr& widget : widgets) {
@ -59,7 +59,7 @@ bool UIHorizontalLayout::internalUpdate()
gap = (m_alignRight) ? -(widget->getMarginRight()+widget->getWidth()) : widget->getMarginLeft(); gap = (m_alignRight) ? -(widget->getMarginRight()+widget->getWidth()) : widget->getMarginLeft();
pos.x += gap; pos.x += gap;
prefferedWidth += gap; preferredWidth += gap;
if(widget->isFixedSize()) { if(widget->isFixedSize()) {
// center it // center it
@ -77,16 +77,16 @@ bool UIHorizontalLayout::internalUpdate()
gap = (m_alignRight) ? -widget->getMarginLeft() : (widget->getWidth() + widget->getMarginRight()); gap = (m_alignRight) ? -widget->getMarginLeft() : (widget->getWidth() + widget->getMarginRight());
gap += m_spacing; gap += m_spacing;
pos.x += gap; pos.x += gap;
prefferedWidth += gap; preferredWidth += gap;
} }
prefferedWidth -= m_spacing; preferredWidth -= m_spacing;
prefferedWidth += parentWidget->getPaddingLeft() + parentWidget->getPaddingRight(); preferredWidth += parentWidget->getPaddingLeft() + parentWidget->getPaddingRight();
if(m_fitChildren && prefferedWidth != parentWidget->getWidth()) { if(m_fitChildren && preferredWidth != parentWidget->getWidth()) {
// must set the preffered width later // must set the preferred width later
g_eventDispatcher.addEvent([=] { g_eventDispatcher.addEvent([=] {
parentWidget->setWidth(prefferedWidth); parentWidget->setWidth(preferredWidth);
}); });
} }

View File

@ -49,7 +49,7 @@ bool UIVerticalLayout::internalUpdate()
Rect clippingRect = parentWidget->getClippingRect(); Rect clippingRect = parentWidget->getClippingRect();
Point pos = (m_alignBottom) ? clippingRect.bottomLeft() : clippingRect.topLeft(); Point pos = (m_alignBottom) ? clippingRect.bottomLeft() : clippingRect.topLeft();
int prefferedHeight = 0; int preferredHeight = 0;
int gap; int gap;
for(const UIWidgetPtr& widget : widgets) { for(const UIWidgetPtr& widget : widgets) {
@ -60,7 +60,7 @@ bool UIVerticalLayout::internalUpdate()
gap = (m_alignBottom) ? -(widget->getMarginBottom()+widget->getHeight()) : widget->getMarginTop(); gap = (m_alignBottom) ? -(widget->getMarginBottom()+widget->getHeight()) : widget->getMarginTop();
pos.y += gap; pos.y += gap;
prefferedHeight += gap; preferredHeight += gap;
if(widget->isFixedSize()) { if(widget->isFixedSize()) {
// center it // center it
@ -78,16 +78,16 @@ bool UIVerticalLayout::internalUpdate()
gap = (m_alignBottom) ? -widget->getMarginTop() : (widget->getHeight() + widget->getMarginBottom()); gap = (m_alignBottom) ? -widget->getMarginTop() : (widget->getHeight() + widget->getMarginBottom());
gap += m_spacing; gap += m_spacing;
pos.y += gap; pos.y += gap;
prefferedHeight += gap; preferredHeight += gap;
} }
prefferedHeight -= m_spacing; preferredHeight -= m_spacing;
prefferedHeight += parentWidget->getPaddingTop() + parentWidget->getPaddingBottom(); preferredHeight += parentWidget->getPaddingTop() + parentWidget->getPaddingBottom();
if(m_fitChildren && prefferedHeight != parentWidget->getHeight()) { if(m_fitChildren && preferredHeight != parentWidget->getHeight()) {
// must set the preffered width later // must set the preferred width later
g_eventDispatcher.addEvent([=] { g_eventDispatcher.addEvent([=] {
parentWidget->setHeight(prefferedHeight); parentWidget->setHeight(preferredHeight);
}); });
} }

View File

@ -1300,10 +1300,10 @@ void UIWidget::onGeometryChange(const Rect& oldRect, const Rect& newRect)
updateText(); updateText();
// move children that is outside the parent rect to inside again // move children that is outside the parent rect to inside again
for(const UIWidgetPtr& child : m_children) { //for(const UIWidgetPtr& child : m_children) {
if(!child->isAnchored()) //if(!child->isAnchored())
child->bindRectToParent(); //child->bindRectToParent();
} //}
} }
void UIWidget::onLayoutUpdate() void UIWidget::onLayoutUpdate()

View File

@ -21,3 +21,80 @@
*/ */
#include "container.h" #include "container.h"
#include "item.h"
Container::Container()
{
m_id = -1;
m_itemId = 0;
m_capacity = 20;
m_name = "Container";
m_hasParent = false;
}
void Container::open(const ContainerPtr& previousContainer)
{
callLuaField("onOpen", previousContainer);
}
void Container::close()
{
callLuaField("onClose");
}
void Container::addItem(const ItemPtr& item)
{
m_items.push_front(item);
updateItemsPositions();
callLuaField("onAddItem", 0, item);
}
void Container::addItems(const std::vector<ItemPtr>& items)
{
for(const ItemPtr& item : items)
m_items.push_back(item);
updateItemsPositions();
}
void Container::updateItem(int slot, const ItemPtr& item)
{
if(slot < 0 || slot >= (int)m_items.size()) {
logTraceError("slot not found");
return;
}
ItemPtr oldItem = m_items[slot];
m_items[slot] = item;
item->setPosition(getSlotPosition(slot));
callLuaField("onUpdateItem", slot, item, oldItem);
}
void Container::removeItem(int slot)
{
if(slot < 0 || slot >= (int)m_items.size()) {
logTraceError("slot not found");
return;
}
ItemPtr item = m_items[slot];
m_items.erase(m_items.begin() + slot);
updateItemsPositions();
callLuaField("onRemoveItem", slot, item);
}
ItemPtr Container::getItem(int slot)
{
if(slot < 0 || slot >= (int)m_items.size())
return nullptr;
return m_items[slot];
}
void Container::updateItemsPositions()
{
for(int slot = 0; slot < (int)m_items.size(); ++slot)
m_items[slot]->setPosition(getSlotPosition(slot));
}

View File

@ -32,6 +32,39 @@ class Container : public LuaObject
public: public:
Container(); Container();
void open(const ContainerPtr& previousContainer);
void close();
void addItem(const ItemPtr& item);
void addItems(const std::vector<ItemPtr>& items);
void updateItem(int slot, const ItemPtr& item);
void removeItem(int slot);
ItemPtr getItem(int slot);
Position getSlotPosition(int slot) { return Position(0xffff, m_id | 0x40, slot); }
void setId(int id) { m_id = id; }
void setCapacity(int capacity) { m_capacity = capacity; }
void setName(std::string name) { m_name = name; }
void setItemId(uint16 itemId) { m_itemId = itemId; }
void setHasParent(bool hasParent) { m_hasParent = hasParent; }
std::string getName() { return m_name; }
int getId() { return m_id; }
int getCapacity() { return m_capacity; }
int getItemsCount() { return m_items.size(); }
uint16 getItemId() { return m_itemId; }
bool hasParent() { return m_hasParent; }
private:
void updateItemsPositions();
int m_id;
int m_capacity;
uint16 m_itemId;
std::string m_name;
bool m_hasParent;
std::deque<ItemPtr> m_items;
}; };
#endif #endif

View File

@ -25,6 +25,7 @@
#include "map.h" #include "map.h"
#include "tile.h" #include "tile.h"
#include "creature.h" #include "creature.h"
#include "container.h"
#include "statictext.h" #include "statictext.h"
#include <framework/core/eventdispatcher.h> #include <framework/core/eventdispatcher.h>
#include <framework/ui/uimanager.h> #include <framework/ui/uimanager.h>
@ -166,30 +167,73 @@ void Game::processCreatureSpeak(const std::string& name, int level, Otc::SpeakTy
g_lua.callGlobalField("g_game", "onCreatureSpeak", name, level, type, message, channelId, creaturePos); g_lua.callGlobalField("g_game", "onCreatureSpeak", name, level, type, message, channelId, creaturePos);
} }
void Game::processOpenContainer(int containerId, int itemId, const std::string& name, int capacity, bool hasParent, const std::vector< ItemPtr >& items) void Game::processOpenContainer(int containerId, int itemId, const std::string& name, int capacity, bool hasParent, const std::vector<ItemPtr>& items)
{ {
g_lua.callGlobalField("g_game", "onOpenContainer", containerId, itemId, name, capacity, hasParent, items); ContainerPtr previousContainer = getContainer(containerId);
ContainerPtr container = ContainerPtr(new Container());
container->setId(containerId);
container->setCapacity(capacity);
container->setName(name);
container->setItemId(itemId);
container->setHasParent(hasParent);
m_containers[containerId] = container;
container->addItems(items);
container->open(previousContainer);
if(previousContainer)
previousContainer->close();
} }
void Game::processCloseContainer(int containerId) void Game::processCloseContainer(int containerId)
{ {
g_lua.callGlobalField("g_game", "onCloseContainer", containerId); ContainerPtr container = getContainer(containerId);
if(!container) {
logTraceError("container not found");
return;
}
auto it = m_containers.find(container->getId());
if(it == m_containers.end() || it->second != container) {
logTraceError("invalid container");
return;
}
m_containers.erase(it);
container->close();
} }
void Game::processContainerAddItem(int containerId, const ItemPtr& item) void Game::processContainerAddItem(int containerId, const ItemPtr& item)
{ {
item->setPosition(Position(65535, containerId + 0x40, 0)); ContainerPtr container = getContainer(containerId);
g_lua.callGlobalField("g_game", "onContainerAddItem", containerId, item); if(!container) {
logTraceError("container not found");
return;
}
container->addItem(item);
} }
void Game::processContainerUpdateItem(int containerId, int slot, const ItemPtr& item) void Game::processContainerUpdateItem(int containerId, int slot, const ItemPtr& item)
{ {
g_lua.callGlobalField("g_game", "onContainerUpdateItem", containerId, slot, item); ContainerPtr container = getContainer(containerId);
if(!container) {
logTraceError("container not found");
return;
}
container->updateItem(slot, item);
} }
void Game::processContainerRemoveItem(int containerId, int slot) void Game::processContainerRemoveItem(int containerId, int slot)
{ {
g_lua.callGlobalField("g_game", "onContainerRemoveItem", containerId, slot); ContainerPtr container = getContainer(containerId);
if(!container) {
logTraceError("container not found");
return;
}
container->removeItem(slot);
} }
void Game::processInventoryChange(int slot, const ItemPtr& item) void Game::processInventoryChange(int slot, const ItemPtr& item)
@ -542,19 +586,37 @@ void Game::useInventoryItemWith(int itemId, const ThingPtr& toThing)
m_protocolGame->sendUseItemWith(pos, itemId, 0, toThing->getPosition(), toThing->getId(), toThing->getStackpos()); m_protocolGame->sendUseItemWith(pos, itemId, 0, toThing->getPosition(), toThing->getId(), toThing->getStackpos());
} }
void Game::open(const ItemPtr& item, int containerId) void Game::open(const ItemPtr& item, const ContainerPtr& previousContainer)
{ {
if(!canPerformGameAction() || !item) if(!canPerformGameAction() || !item)
return; return;
m_protocolGame->sendUseItem(item->getPosition(), item->getId(), item->getStackpos(), containerId); int id = 0;
if(!previousContainer) {
// find a free container id
while(m_containers.find(id) != m_containers.end())
id++;
} else {
id = previousContainer->getId();
}
m_protocolGame->sendUseItem(item->getPosition(), item->getId(), item->getStackpos(), id);
} }
void Game::upContainer(int containerId) void Game::openParent(const ContainerPtr& container)
{ {
if(!canPerformGameAction()) if(!canPerformGameAction())
return; return;
m_protocolGame->sendUpContainer(containerId);
m_protocolGame->sendUpContainer(container->getId());
}
void Game::close(const ContainerPtr& container)
{
if(!canPerformGameAction())
return;
m_protocolGame->sendCloseContainer(container->getId());
} }
void Game::refreshContainer() void Game::refreshContainer()

View File

@ -139,8 +139,9 @@ public:
void useInventoryItemWith(int itemId, const ThingPtr& toThing); void useInventoryItemWith(int itemId, const ThingPtr& toThing);
// container related // container related
void open(const ItemPtr& item, int containerId); void open(const ItemPtr& item, const ContainerPtr& previousContainer);
void upContainer(int containerId); void openParent(const ContainerPtr& container);
void close(const ContainerPtr& container);
void refreshContainer(); void refreshContainer();
// attack/follow related // attack/follow related
@ -218,6 +219,7 @@ public:
bool isFollowing() { return !!m_followingCreature; } bool isFollowing() { return !!m_followingCreature; }
ContainerPtr getContainer(int index) { return m_containers[index]; } ContainerPtr getContainer(int index) { return m_containers[index]; }
std::map<int, ContainerPtr> getContainers() { return m_containers; }
CreaturePtr getAttackingCreature() { return m_attackingCreature; } CreaturePtr getAttackingCreature() { return m_attackingCreature; }
CreaturePtr getFollowingCreature() { return m_followingCreature; } CreaturePtr getFollowingCreature() { return m_followingCreature; }
int getServerBeat() { return m_serverBeat; } int getServerBeat() { return m_serverBeat; }

View File

@ -56,8 +56,10 @@ const TilePtr& Thing::getTile()
ContainerPtr Thing::getParentContainer() ContainerPtr Thing::getParentContainer()
{ {
if(m_position.x == 0xFFFF && m_position.y & 0x40) if(m_position.x == 0xffff && m_position.y & 0x40) {
return g_game.getContainer(m_position.z); int containerId = m_position.y ^ 0x40;
return g_game.getContainer(containerId);
}
return nullptr; return nullptr;
} }

View File

@ -95,7 +95,8 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassStaticFunction("g_game", "useInventoryItem", std::bind(&Game::useInventoryItem, &g_game, _1)); g_lua.bindClassStaticFunction("g_game", "useInventoryItem", std::bind(&Game::useInventoryItem, &g_game, _1));
g_lua.bindClassStaticFunction("g_game", "useInventoryItemWith", std::bind(&Game::useInventoryItemWith, &g_game, _1, _2)); g_lua.bindClassStaticFunction("g_game", "useInventoryItemWith", std::bind(&Game::useInventoryItemWith, &g_game, _1, _2));
g_lua.bindClassStaticFunction("g_game", "open", std::bind(&Game::open, &g_game, _1, _2)); g_lua.bindClassStaticFunction("g_game", "open", std::bind(&Game::open, &g_game, _1, _2));
g_lua.bindClassStaticFunction("g_game", "upContainer", std::bind(&Game::upContainer, &g_game, _1)); g_lua.bindClassStaticFunction("g_game", "openParent", std::bind(&Game::openParent, &g_game, _1));
g_lua.bindClassStaticFunction("g_game", "close", std::bind(&Game::close, &g_game, _1));
g_lua.bindClassStaticFunction("g_game", "refreshContainer", std::bind(&Game::refreshContainer, &g_game)); g_lua.bindClassStaticFunction("g_game", "refreshContainer", std::bind(&Game::refreshContainer, &g_game));
g_lua.bindClassStaticFunction("g_game", "attack", std::bind(&Game::attack, &g_game, _1)); g_lua.bindClassStaticFunction("g_game", "attack", std::bind(&Game::attack, &g_game, _1));
g_lua.bindClassStaticFunction("g_game", "cancelAttack", std::bind(&Game::cancelAttack, &g_game)); g_lua.bindClassStaticFunction("g_game", "cancelAttack", std::bind(&Game::cancelAttack, &g_game));
@ -147,6 +148,8 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassStaticFunction("g_game", "isDead", std::bind(&Game::isDead, &g_game)); g_lua.bindClassStaticFunction("g_game", "isDead", std::bind(&Game::isDead, &g_game));
g_lua.bindClassStaticFunction("g_game", "isAttacking", std::bind(&Game::isAttacking, &g_game)); g_lua.bindClassStaticFunction("g_game", "isAttacking", std::bind(&Game::isAttacking, &g_game));
g_lua.bindClassStaticFunction("g_game", "isFollowing", std::bind(&Game::isFollowing, &g_game)); g_lua.bindClassStaticFunction("g_game", "isFollowing", std::bind(&Game::isFollowing, &g_game));
g_lua.bindClassStaticFunction("g_game", "getContainer", std::bind(&Game::getContainer, &g_game, _1));
g_lua.bindClassStaticFunction("g_game", "getContainers", std::bind(&Game::getContainers, &g_game));
g_lua.bindClassStaticFunction("g_game", "getAttackingCreature", std::bind(&Game::getAttackingCreature, &g_game)); g_lua.bindClassStaticFunction("g_game", "getAttackingCreature", std::bind(&Game::getAttackingCreature, &g_game));
g_lua.bindClassStaticFunction("g_game", "getFollowingCreature", std::bind(&Game::getFollowingCreature, &g_game)); g_lua.bindClassStaticFunction("g_game", "getFollowingCreature", std::bind(&Game::getFollowingCreature, &g_game));
g_lua.bindClassStaticFunction("g_game", "getServerBeat", std::bind(&Game::getServerBeat, &g_game)); g_lua.bindClassStaticFunction("g_game", "getServerBeat", std::bind(&Game::getServerBeat, &g_game));
@ -165,6 +168,26 @@ void OTClient::registerLuaFunctions()
g_lua.registerClass<ProtocolGame, Protocol>(); g_lua.registerClass<ProtocolGame, Protocol>();
g_lua.registerClass<Container>(); g_lua.registerClass<Container>();
g_lua.bindClassStaticFunction<Container>("create", []{ return ContainerPtr(new Container); });
g_lua.bindClassMemberFunction<Container>("open", &Container::open);
g_lua.bindClassMemberFunction<Container>("close", &Container::close);
g_lua.bindClassMemberFunction<Container>("addItem", &Container::addItem);
g_lua.bindClassMemberFunction<Container>("addItems", &Container::addItems);
g_lua.bindClassMemberFunction<Container>("updateItem", &Container::updateItem);
g_lua.bindClassMemberFunction<Container>("removeItem", &Container::removeItem);
g_lua.bindClassMemberFunction<Container>("getItem", &Container::getItem);
g_lua.bindClassMemberFunction<Container>("getSlotPosition", &Container::getSlotPosition);
g_lua.bindClassMemberFunction<Container>("setId", &Container::setId);
g_lua.bindClassMemberFunction<Container>("setCapacity", &Container::setCapacity);
g_lua.bindClassMemberFunction<Container>("setName", &Container::setName);
g_lua.bindClassMemberFunction<Container>("setItemId", &Container::setItemId);
g_lua.bindClassMemberFunction<Container>("setHasParent", &Container::setHasParent);
g_lua.bindClassMemberFunction<Container>("getName", &Container::getName);
g_lua.bindClassMemberFunction<Container>("getId", &Container::getId);
g_lua.bindClassMemberFunction<Container>("getCapacity", &Container::getCapacity);
g_lua.bindClassMemberFunction<Container>("getItemsCount", &Container::getItemsCount);
g_lua.bindClassMemberFunction<Container>("getItemId", &Container::getItemId);
g_lua.bindClassMemberFunction<Container>("hasParent", &Container::hasParent);
g_lua.registerClass<Thing>(); g_lua.registerClass<Thing>();
g_lua.bindClassMemberFunction<Thing>("setId", &Thing::setId); g_lua.bindClassMemberFunction<Thing>("setId", &Thing::setId);

View File

@ -35,18 +35,17 @@ void UIItem::drawSelf()
UIWidget::drawSelf(); UIWidget::drawSelf();
if(m_item) { if(m_item) {
Point topLeft = m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top); Rect drawRect = getClippingRect();
float scaleFactor = std::min(drawRect.width() / 32.0f, drawRect.height() / 32.0f);
g_painter.setColor(Color::white); g_painter.setColor(Color::white);
m_item->draw(topLeft, 1, true); m_item->draw(drawRect.topLeft(), scaleFactor, true);
if(m_font && m_item->isStackable() && m_item->getCount() > 1) { if(m_font && m_item->isStackable() && m_item->getCount() > 1) {
std::string count = Fw::tostring(m_item->getCount()); std::string count = Fw::tostring(m_item->getCount());
g_painter.setColor(Color(231, 231, 231)); g_painter.setColor(Color(231, 231, 231));
m_font->drawText(count, Rect(m_rect.topLeft(), m_rect.bottomRight() - Point(3, 0)), Fw::AlignBottomRight); m_font->drawText(count, Rect(m_rect.topLeft(), m_rect.bottomRight() - Point(3, 0)), Fw::AlignBottomRight);
} }
//m_font->renderText(Fw::unsafeCast<std::string>(m_item->getId()), m_rect);
} }
} }