implement npc trade interface

master
AndreFaramir 12 years ago
parent 92bd1aba54
commit 9c038e2f39

@ -22,6 +22,7 @@ Module
- game_battle
- game_minimap
- game_hotkeys
- game_npctrade
@onLoad: |
importStyle 'styles/items.otui'

@ -0,0 +1,13 @@
void processOpenNpcTrade(const std::vector<std::tuple<ItemPtr, std::string, int, int, int>>& items);
void processPlayerGoods(int money, const std::vector<std::tuple<ItemPtr, int>>& goods);
void processCloseNpcTrade();
g_lua.callGlobalField("g_game", "onOpenNpcTrade", items);
g_lua.callGlobalField("g_game", "onPlayerGoods", goods);
g_lua.callGlobalField("g_game", "onCloseNpcTrade");
// npc trade related
void inspectNpcTrade(const ItemPtr& item);
void buyItem(const ItemPtr& item, int amount, bool ignoreCapacity, bool buyWithBackpack);
void sellItem(const ItemPtr& item, int amount, bool ignoreEquipped);
void closeNpcTrade();

@ -0,0 +1,316 @@
NPCTrade = {}
local npcWindow
local itemsPanel
local radioTabs
local radioItems
local buyTab
local sellTab
local searchText
local setupPanel
local quantity
local quantityScroll
local nameLabel
local priceLabel
local moneyGoods
local moneyLabel
local weightLabel
local capacityLabel
local offerSelected
local setupButton
local cacheItems
local cacheGoods
local buyWithBackpack = false
local ignoreCapacity = false
local ignoreEquipped = true
-- public functions
function NPCTrade.init()
cacheItems = {}
cacheGoods = {}
npcWindow = displayUI('npctrade.otui')
npcWindow:setVisible(false)
itemsPanel = npcWindow:recursiveGetChildById('itemsPanel')
buyTab = npcWindow:getChildById('buyTab')
sellTab = npcWindow:getChildById('sellTab')
searchText = npcWindow:getChildById('searchText')
setupPanel = npcWindow:recursiveGetChildById('setupPanel')
quantityLabel = setupPanel:getChildById('quantity')
quantityScroll = setupPanel:getChildById('quantityScroll')
nameLabel = setupPanel:getChildById('name')
priceLabel = setupPanel:getChildById('price')
moneyLabel = setupPanel:getChildById('money')
weightLabel = setupPanel:getChildById('weight')
capacityLabel = setupPanel:getChildById('capacity')
setupButton = setupPanel:getChildById('setupButton')
radioTabs = RadioGroup.create()
radioTabs:addWidget(buyTab)
radioTabs:addWidget(sellTab)
radioTabs:selectWidget(buyTab)
connect(g_game, { onOpenNpcTrade = NPCTrade.onOpenNpcTrade,
onPlayerGoods = NPCTrade.onPlayerGoods,
onCloseNpcTrade = NPCTrade.onCloseNpcTrade } )
end
function NPCTrade.terminate()
radioTabs:destroy()
radioTabs = nil
npcWindow:destroy()
npcWindow = nil
itemsPanel = nil
buyButton = nil
sellButton = nil
searchText = nil
setupPanel = nil
quantityLabel = nil
quantityScroll = nil
nameLabel = nil
priceLabel = nil
moneyLabel = nil
weightLabel = nil
capacityLabel = nil
offerSelected = nil
setupButton = nil
cacheItems = nil
cacheGoods = nil
disconnect(g_game, { onOpenNpcTrade = NPCTrade.onOpenNpcTrade,
onPlayerGoods = NPCTrade.onPlayerGoods,
onCloseNpcTrade = NPCTrade.onCloseNpcTrade } )
end
-- private functions
function NPCTrade.show()
if g_game.isOnline() then
npcWindow:show()
npcWindow:raise()
end
end
function NPCTrade.hide()
npcWindow:hide()
end
function NPCTrade.setList(widget, checked)
setupButton:setText(widget:getText())
widget:setOn(checked)
NPCTrade.createItemsOnPanel()
NPCTrade.resetSetup()
NPCTrade.refreshItemsPanel()
end
function NPCTrade.resetSetup()
nameLabel:clearText()
weightLabel:clearText()
priceLabel:clearText()
searchText:clearText()
if offerSelected then
radioItems.selectedWidget:setChecked(false)
offerSelected = nil
end
setupPanel:disable()
end
function NPCTrade.updateSetup()
if offerSelected then
if radioItems.selectedWidget:isEnabled() then
if setupButton:getText() == 'Buy' then
quantityScroll:setMaximum(math.max(0, math.min(100, math.floor(moneyGoods/NPCTrade.getOfferPrice(offerSelected)))))
else
quantityScroll:setMaximum(math.max(0, math.min(100, cacheGoods[offerSelected[1]:getId()])))
end
else
NPCTrade.resetSetup()
end
end
end
function NPCTrade.getOfferPrice(offer)
if setupButton:getText() == 'Buy' then
local price = offer[4]
if buyWithBackpack then
if offer[1]:isStackable() then
return price*quantityScroll:getValue() + 20;
else
return price*quantityScroll:getValue() + math.ceil(quantityScroll:getValue()/20)*20
end
else
return price*quantityScroll:getValue()
end
else
return offer[5]*quantityScroll:getValue()
end
end
function NPCTrade.setItem(widget)
offerSelected = widget.offer
local offer = widget.offer
local price = NPCTrade.getOfferPrice(widget.offer)
local freeCapacity = g_game.getLocalPlayer():getFreeCapacity()
nameLabel:setText(offer[2])
weightLabel:setText(string.format("%.2f", offer[3]/100) .. " oz")
priceLabel:setText(price .. " gold")
capacityLabel:setText(string.format("%.2f", freeCapacity) .. " oz")
quantityLabel:setText(1)
quantityScroll:setValue(1)
NPCTrade.updateSetup()
setupPanel:enable()
end
function NPCTrade.setQuantity(quantity)
if quantityLabel and offerSelected then
local price = NPCTrade.getOfferPrice(offerSelected)
quantityLabel:setText(quantity)
weightLabel:setText(string.format("%.2f", offerSelected[3]*quantity/100) .. " oz")
priceLabel:setText(price .. " gold")
end
end
function NPCTrade.setupButton()
if setupButton:getText() == 'Buy' then
g_game.buyItem(offerSelected[1], quantityScroll:getValue(), buyWithBackpack, ignoreCapacity)
else
g_game.sellItem(offerSelected[1], quantityScroll:getValue(), ignoreEquipped)
end
end
function NPCTrade.onOpenNpcTrade(items)
-- items[item] = item
-- item[1] = ItemPtr
-- item[2] = name
-- item[3] = weight
-- item[4] = buyPrice
-- item[5] = sellPrice
cacheItems = items
NPCTrade.createItemsOnPanel()
NPCTrade.show()
end
function NPCTrade.swithBuyWithBackpack()
buyWithBackpack = not buyWithBackpack
if offerSelected then
priceLabel:setText(NPCTrade.getOfferPrice(offerSelected) .. " gold")
end
return true
end
function NPCTrade.itemPopup(self, mousePosition, mouseButton)
if mouseButton == MouseRightButton then
local menu = createWidget('PopupMenu')
menu:addOption('Look', function() return g_game.inspectNpcTrade(self.offer[1]) end)
menu:addSeparator()
if setupButton:getText() == 'Buy' then
menu:addOption((buyWithBackpack and 'Buy no backpack' or 'Buy with backpack'), NPCTrade.swithBuyWithBackpack)
menu:addOption((ignoreCapacity and 'Consider capacity' or 'Ignore capacity'), function() ignoreCapacity = not ignoreCapacity return true end)
else
menu:addOption((ignoreEquipped and 'Consider equipped' or 'Ignore equipped'), function() ignoreEquipped = not ignoreEquipped return true end)
end
menu:display(mousePosition)
end
end
function NPCTrade.createItemsOnPanel()
NPCTrade.resetSetup()
offerSelected = nil
itemsPanel:destroyChildren()
radioItems = RadioGroup.create()
for i, v in pairs(cacheItems) do
local price = NPCTrade.getOfferPrice(v)
if price >= 0 then
local itemBox = createWidget('NPCItemBox', itemsPanel)
itemBox.offer = v
itemBox:getChildById('item'):setItem(v[1])
itemBox:getChildById('nameLabel'):setText(v[2])
itemBox:getChildById('weightLabel'):setText(string.format("%.2f", v[3]/100) .. " oz")
itemBox:getChildById('priceLabel'):setText(price .. " gold")
itemBox.onMouseRelease = NPCTrade.itemPopup
itemBox:getChildById('item').onMouseRelease = function (self, mousePosition, mouseButton) NPCTrade.itemPopup(itemBox, mousePosition, mouseButton) end
radioItems:addWidget(itemBox)
end
end
end
function NPCTrade.searchFilter(filter)
local items = itemsPanel:getChildCount()
for i = 1, items do
local itemWidget = itemsPanel:getChildByIndex(i)
if filter ~= "" then
if string.find(itemWidget.offer[2], filter) then
itemWidget:show()
else
itemWidget:hide()
end
else
itemWidget:show()
end
end
end
function NPCTrade.refreshItemsPanel()
if setupButton:getText() == 'Buy' then
local items = itemsPanel:getChildCount()
for i = 1, items do
local itemWidget = itemsPanel:getChildByIndex(i)
if moneyGoods < NPCTrade.getOfferPrice(itemWidget.offer) then
itemWidget:disable()
else
itemWidget:enable()
end
end
else
local items = itemsPanel:getChildCount()
for i = 1, items do
local itemWidget = itemsPanel:getChildByIndex(i)
if cacheGoods[itemWidget.offer[1]:getId()] then
itemWidget:enable()
else
itemWidget:disable()
end
end
end
end
function NPCTrade.onPlayerGoods(money, goods)
moneyGoods = money
moneyLabel:setText(money .. " gold")
local freeCapacity = g_game.getLocalPlayer():getFreeCapacity()
capacityLabel:setText(string.format("%.2f", freeCapacity) .. " oz")
cacheGoods = {}
for i,v in pairs(goods) do
cacheGoods[v[1]:getId()] = v[2]
end
NPCTrade.refreshItemsPanel()
NPCTrade.updateSetup()
end
function NPCTrade.onCloseNpcTrade()
NPCTrade.hide()
end
-- void inspectNpcTrade(const ItemPtr& item);
-- void buyItem(const ItemPtr& item, int amount, bool ignoreCapacity, bool buyWithBackpack);
-- void sellItem(const ItemPtr& item, int amount, bool ignoreEquipped);
-- void closeNpcTrade();

@ -0,0 +1,15 @@
Module
name: game_npctrade
description: NPC trade interface
author: OTClient team
website: https://github.com/edubart/otclient
dependencies:
- game
@onLoad: |
dofile 'npctrade'
NPCTrade.init()
@onUnload: |
NPCTrade.terminate()

@ -0,0 +1,237 @@
NPCOfferLabel < Label
anchors.left: prev.right
anchors.top: prev.top
margin-left: 5
text-auto-resize: true
NPCPanel < ScrollablePanel
image-source: /core_styles/styles/images/panel_flat.png
image-border: 1
NPCItemBox < UICheckBox
border-width: 1
border-color: #000000
@onCheckChange: NPCTrade.setItem(self)
Item
id: item
phantom: true
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
Label
id: nameLabel
phantom: true
text: cavalo
anchors.top: prev.bottom
anchors.horizontalCenter: parent.horizontalCenter
text-auto-resize: true
margin-top: 5
Label
id: weightLabel
phantom: true
text: 8.00 oz
anchors.top: prev.bottom
anchors.horizontalCenter: parent.horizontalCenter
text-auto-resize: true
margin-top: 5
Label
id: priceLabel
phantom: true
text: 200 gold
anchors.top: prev.bottom
anchors.horizontalCenter: parent.horizontalCenter
text-auto-resize: true
margin-top: 5
$checked:
border-color: #FFFFFF
$hover !checked:
border-color: #AAAAAA
MainWindow
id: npcWindow
text: NPC Trade
size: 550 550
@onEscape: NPCTrade.hide()
TabButton
id: buyTab
tooltip: List of items that you're able to buy
text: Buy
anchors.left: parent.left
anchors.right: parent.horizontalCenter
anchors.top: parent.top
margin-right: 5
margin-top: 5
@onCheckChange: NPCTrade.setList(self, self:isChecked())
TabButton
id: sellTab
tooltip: List of items that you're able to sell
text: Sell
anchors.left: parent.horizontalCenter
anchors.right: parent.right
anchors.top: parent.top
margin-left: 5
margin-top: 5
@onCheckChange: NPCTrade.setList(self, self:isChecked())
Label
id: searchLabel
text: Search:
anchors.left: parent.left
anchors.top: prev.bottom
text-auto-resize: true
margin-top: 5
margin-left: 2
TextEdit
id: searchText
width: 200
anchors.left: prev.right
anchors.top: prev.top
margin-left: 5
@onTextChange: NPCTrade.searchFilter(self:getText())
NPCPanel
height: 250
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 5
VerticalScrollBar
id: itemsPanelListScrollBar
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
step: 14
pixels-scroll: true
NPCPanel
id: itemsPanel
height: 250
anchors.left: parent.left
anchors.right: prev.left
anchors.top: parent.top
anchors.bottom: parent.bottom
vertical-scrollbar: itemsPanelListScrollBar
layout:
type: grid
cell-size: 160 90
flow: true
auto-spacing: true
FlatPanel
id: setupPanel
height: 150
enabled: false
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 5
Label
id: quantityLabel
text: Quantity
anchors.left: parent.left
anchors.top: parent.top
text-auto-resize: true
margin-top: 5
margin-left: 2
NPCOfferLabel
id: quantity
HorizontalScrollBar
id: quantityScroll
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 2
minimum: 1
maximum: 100
value: 1
step: 1
@onValueChange: NPCTrade.setQuantity(self:getValue())
Label
id: nameLabel
text: Name
anchors.left: parent.left
anchors.top: prev.bottom
text-auto-resize: true
margin-top: 5
margin-left: 2
NPCOfferLabel
id: name
Label
id: priceLabel
text: Price
anchors.left: parent.left
anchors.top: prev.bottom
text-auto-resize: true
margin-top: 5
margin-left: 2
NPCOfferLabel
id: price
Label
id: moneyLabel
text: Money
anchors.left: parent.left
anchors.top: prev.bottom
text-auto-resize: true
margin-top: 5
margin-left: 2
NPCOfferLabel
id: money
Label
id: weightLabel
text: Weight
anchors.left: parent.left
anchors.top: prev.bottom
text-auto-resize: true
margin-top: 5
margin-left: 2
NPCOfferLabel
id: weight
Label
id: capacityLabel
text: Capacity
anchors.left: parent.left
anchors.top: prev.bottom
text-auto-resize: true
margin-top: 5
margin-left: 2
NPCOfferLabel
id: capacity
Button
id: setupButton
text: Buy
width: 64
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: prev.bottom
@onClick: NPCTrade.setupButton()
Button
text: Close
width: 64
anchors.right: parent.right
anchors.bottom: parent.bottom
@onClick: NPCTrade.hide()

@ -243,6 +243,9 @@ void OTClient::registerLuaFunctions()
g_lua.registerClass<Item, Thing>();
g_lua.bindClassStaticFunction<Item>("create", &Item::create);
g_lua.bindClassMemberFunction<Item>("getCount", &Item::getCount);
g_lua.bindClassMemberFunction<Item>("getId", &Item::getId);
g_lua.bindClassMemberFunction<Item>("isStackable", &Item::isStackable);
g_lua.registerClass<Effect, Thing>();
g_lua.registerClass<Missile, Thing>();

Loading…
Cancel
Save