More on Market (far from done), Minor Fixes, Edited Outfits Module, Some Cosmetics.

* Started building the market UI.
* More work on the market functionality.
* Fixes to the market protocol. (Known issue: if I use safeSend method from Market (like so: MarketProtocol.send~) is thinks it is a bot).
* Fixes to the market offer class.
* Outfit window will no longer display the mount box if you are using protocol < 870.
* Added getFeature to playermount module.
* Added isMarketable and getMarketData to the lua binding.
* Added lua casts for MarketData.
* Fixed typo in the module manager.
* Added new 'light flat panel' for more variation (can change later) will require some graphics for market.
* Added new functions to table lib.
* Fixed some styling issues from previous commits.
This commit is contained in:
BeniS 2012-07-20 06:54:24 +12:00
parent 9dc88de6b0
commit 6293a49f8f
34 changed files with 744 additions and 99 deletions

View File

@ -146,7 +146,7 @@ function ModuleManager.unloadCurrentModule()
end end
function ModuleManager.reloadAllModules() function ModuleManager.reloadAllModules()
g_modules.g_modules.reloadModules() g_modules.reloadModules()
ModuleManager.refreshLoadedModules() ModuleManager.refreshLoadedModules()
ModuleManager.show() ModuleManager.show()
end end

View File

@ -74,6 +74,7 @@ function Options.init()
optionsWindow = g_ui.displayUI('options.otui') optionsWindow = g_ui.displayUI('options.otui')
optionsWindow:hide() optionsWindow:hide()
optionsButton = TopMenu.addLeftButton('optionsButton', tr('Options') .. ' (Ctrl+D)', 'options.png', Options.toggle) optionsButton = TopMenu.addLeftButton('optionsButton', tr('Options') .. ' (Ctrl+D)', 'options.png', Options.toggle)
optionsTabBar = optionsWindow:getChildById('optionsTabBar') optionsTabBar = optionsWindow:getChildById('optionsTabBar')
optionsTabBar:setContentWidget(optionsWindow:getChildById('optionsTabContent')) optionsTabBar:setContentWidget(optionsWindow:getChildById('optionsTabContent'))

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -15,3 +15,7 @@ ScrollableFlatPanel < ScrollablePanel
ParticlesFlatPanel < Panel ParticlesFlatPanel < Panel
image-source: /images/panel_flat.png image-source: /images/panel_flat.png
image-border: 1 image-border: 1
LightFlatPanel < Panel
image-source: /images/panel_lightflat.png
image-border: 1

View File

@ -41,6 +41,18 @@ function table.find(t, value)
end end
end end
function table.findKey(t, key)
if t and type(t) == 'table' then
for k,v in pairs(t) do
if k == key then return k end
end
end
end
function table.hasKey(t, key)
return table.findKey(t, key) ~= nil
end
function table.removevalue(t, value) function table.removevalue(t, value)
for k,v in pairs(t) do for k,v in pairs(t) do
if v == value then if v == value then
@ -59,7 +71,7 @@ function table.compare(t, other)
end end
function table.empty(t) function table.empty(t)
if(t) then if t and type(t) == 'table' then
return next(t) == nil return next(t) == nil
end end
return true return true

View File

@ -5,8 +5,8 @@ ExitWindow < MainWindow
Label Label
!text: tr('If you shut down the program, you character might stay in the game.\nClick on "Logout" to ensure that you character leaves the game property.\nClick on "Exit" if you want to exit the program without logging out your character.') !text: tr('If you shut down the program, you character might stay in the game.\nClick on "Logout" to ensure that you character leaves the game property.\nClick on "Exit" if you want to exit the program without logging out your character.')
width: 550 width: 500
height: 110 height: 45
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
margin-left: 10 margin-left: 10

View File

@ -5,7 +5,7 @@ LogoutWindow < MainWindow
Label Label
!text: tr('Are you sure you want to logout?') !text: tr('Are you sure you want to logout?')
width: 300 width: 200
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
margin-left: 30 margin-left: 30

View File

@ -1,61 +1,262 @@
Market = {} Market = {}
g_ui.importStyle('market.otui')
g_ui.importStyle('ui/general/markettabs.otui')
g_ui.importStyle('ui/general/marketbuttons.otui')
local marketWindow local marketWindow
local mainTabBar
local marketOffersPanel
local selectionTabBar
local browsePanel
local searchPanel
local displaysTabBar
local itemOffersPanel
local itemDetailsPanel
local itemStatsPanel
local myOffersPanel
local offersTabBar
local currentOffersPanel
local offerHistoryPanel
local marketOffers = {}
local depot = {}
local information ={}
local selectedItem
local nameLabel
local itemsPanel
local radioItems
local function clearSelectedItem()
if selectedItem then
nameLabel:clearText()
radioItems:selectWidget(nil)
selectedItem.setItem(nil)
end
end
local function loadMarketItems()
itemsPanel = marketWindow:recursiveGetChildById('itemsPanel')
local layout = itemsPanel:getLayout()
layout:disableUpdates()
clearSelectedItem()
itemsPanel:destroyChildren()
if radioItemSet then
radioItemSet:destroy()
end
radioItemSet = UIRadioGroup.create()
-- TODO: populate with dat items
layout:enableUpdates()
layout:update()
end
local function loadDepotItems(depotItems)
information.depotItems = {}
for _, data in pairs(depotItems) do
local item = Item.create(data[1])
if not item then
break
end
item:setCount(data[2])
local marketData = item:getMarketData()
if not table.empty(marketData) then
local newItem = {
ptr = item,
marketData = marketData
}
table.insert(information.depotItems, newItem)
end
end
end
function Market.init() function Market.init()
g_ui.importStyle('market.otui') marketWindow = g_ui.createWidget('MarketWindow', rootWidget)
marketWindow:hide()
nameLabel = marketWindow:recursiveGetChildById('nameLabel')
-- TODO: clean this up into functions
-- setup main tabs
mainTabBar = marketWindow:getChildById('mainTabBar')
mainTabBar:setContentWidget(marketWindow:getChildById('mainTabContent'))
-- setup 'Market Offer' section tabs
marketOffersPanel = g_ui.loadUI('ui/marketoffers.otui')
mainTabBar:addTab(tr('Market Offers'), marketOffersPanel)
selectionTabBar = marketOffersPanel:getChildById('leftTabBar')
selectionTabBar:setContentWidget(marketOffersPanel:getChildById('leftTabContent'))
browsePanel = g_ui.loadUI('ui/marketoffers/browse.otui')
selectionTabBar:addTab(tr('Browse'), browsePanel)
searchPanel = g_ui.loadUI('ui/marketoffers/search.otui')
selectionTabBar:addTab(tr('Search'), searchPanel)
displaysTabBar = marketOffersPanel:getChildById('rightTabBar')
displaysTabBar:setContentWidget(marketOffersPanel:getChildById('rightTabContent'))
itemOffersPanel = g_ui.loadUI('ui/marketoffers/itemoffers.otui')
displaysTabBar:addTab(tr('Offers'), itemOffersPanel)
itemDetailsPanel = g_ui.loadUI('ui/marketoffers/itemdetails.otui')
displaysTabBar:addTab(tr('Details'), itemDetailsPanel)
itemStatsPanel = g_ui.loadUI('ui/marketoffers/itemstats.otui')
displaysTabBar:addTab(tr('Statistics'), itemStatsPanel)
-- setup 'My Offer' section tabs
myOffersPanel = g_ui.loadUI('ui/myoffers.otui')
mainTabBar:addTab(tr('My Offers'), myOffersPanel)
offersTabBar = myOffersPanel:getChildById('offersTabBar')
offersTabBar:setContentWidget(myOffersPanel:getChildById('offersTabContent'))
currentOffersPanel = g_ui.loadUI('ui/myoffers/currentoffers.otui')
offersTabBar:addTab(tr('Current Offers'), currentOffersPanel)
offerHistoryPanel = g_ui.loadUI('ui/myoffers/offerhistory.otui')
offersTabBar:addTab(tr('Offer History'), offerHistoryPanel)
end end
function Market.terminate() function Market.terminate()
marketWindow = nil if marketWindow then
marketWindow:destroy()
marketWindow = nil
end
mainTabBar = nil
marketOffersPanel = nil
selectionTabBar = nil
browsePanel = nil
searchPanel = nil
displaysTabBar = nil
itemOffersPanel = nil
itemDetailsPanel = nil
itemStatsPanel = nil
myOffersPanel = nil
offersTabBar = nil
currentOffersPanel = nil
offerHistoryPanel = nil
marketOffers = {}
depotItems = {}
information = {}
itemsPanel = nil
nameLabel = nil
radioItems = nil
selectedItem = nil
Market = nil Market = nil
end end
function Market.onMarketEnter(depotItems, offers, balance) function Market.updateOffers(offers)
-- open market window for k, offer in pairs(offers) do
-- populate market? if offer and offer:getAction() == MarketAction.Buy then
print('onMarketEnter') table.insert(marketOffers[MarketAction.Buy], offer)
print(offers) else
print(balance) table.insert(marketOffers[MarketAction.Sell], offer)
print('depotItems:') end
for k, item in pairs(depotItems) do
print('id- '..item[1])
print('count- '..item[2])
end end
for _, offers in pairs(marketOffers) do
for _, offer in pairs(offers) do
print(' counter: '..offer:getCounter()..' | timestamp: '..offer:getTimeStamp()..' | item: '..offer:getItem():getId()..' | action: '..offer:getAction()..' | amount: '..offer:getAmount()..' | price: '..offer:getPrice()..' | player: '..offer:getPlayer()..' | state: '..offer:getState())
end
end
-- TODO: refresh all widget windows
end
function Market.updateDetails(itemId, descriptions, purchaseStats, saleStats)
-- TODO: refresh all widget windows
end
function Market.updateSelectedItem(newItem)
local itemDisplay = marketWindow:recursiveGetChildById('selectedItem')
local itemName = marketWindow:recursiveGetChildById('nameLabel')
selectedItem = newItem
if not table.empty(selectedItem) then
if selectedItem.ptr then
itemDisplay:setItem(selectedItem.ptr)
itemName:setText(tr(selectedItem.name))
MarketProtocol.sendMarketBrowse(selectedItem.ptr:getId()) -- send sprite id browsed
end
else
itemDisplay:setItem(nil)
itemName:setText(tr('No item selected.'))
end
end
function Market.onMarketEnter(depotItems, offers, balance)
-- TODO: populate market?
if marketWindow:isVisible() then
return
end
marketOffers[MarketAction.Buy] = {}
marketOffers[MarketAction.Sell] = {}
information.balance = balance
information.totalOffers = offers
loadMarketItems()
loadDepotItems(depotItems)
-- TODO: if you are already viewing an item on market enter it must recheck the current item
if selectedItem and selectedItem:isChecked() then
selectedItem:setChecked(false)
selectedItem:setChecked(true)
end
--MarketProtocol.sendMarketBrowse(645)
marketWindow:show()
end end
function Market.onMarketLeave() function Market.onMarketLeave()
-- close market window? marketWindow:hide()
print('onMarketLeave')
end end
function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats) function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats)
-- populate market widget Market.updateDetails(itemId, descriptions, purchaseStats, saleStats)
print('onMarketDetail')
print(itemId) print('')
print('[onMarketDetail]')
print('itemId: '..itemId)
print('descriptions:') print('descriptions:')
for k, desc in pairs(descriptions) do for k, desc in pairs(descriptions) do
print('type- '..desc[1]) print(' type: '..desc[1]..' | description: '..desc[2])
print('description- '..desc[2])
end end
print('purchaseStats:') print('purchaseStats:')
for k, stat in pairs(purchaseStats) do for k, stat in pairs(purchaseStats) do
print('transactions- '..stat[1]) print(' transactions: '..stat[1])
print('total price- '..stat[2]) print(' total price: '..stat[2])
print('highest price- '..stat[3]) print(' highest price: '..stat[3])
print('lowest price- '..stat[4]) print(' lowest price: '..stat[4])
end end
print('saleStats:') print('saleStats:')
for k, stat in pairs(saleStats) do for k, stat in pairs(saleStats) do
print('transactions- '..stat[1]) print(' transactions: '..stat[1])
print('total price- '..stat[2]) print(' total price: '..stat[2])
print('highest price- '..stat[3]) print(' highest price: '..stat[3])
print('lowest price- '..stat[4]) print(' lowest price: '..stat[4])
end end
end end
function Market.onMarketBrowse(offers) function Market.onMarketBrowse(offers)
-- populate market widget Market.updateOffers(offers)
print('onMarketBrowse')
end end
function Market.onItemBoxChecked(widget)
if widget:isChecked() then
Market.updateSelectedItem(widget.item)
end
end

View File

@ -1,29 +1,26 @@
MarketWindow < MainWindow MarketWindow < MainWindow
id: marketWindow id: marketWindow
!text: tr('Market') !text: tr('Market')
size: 350 155 size: 680 460
Label @onEnter: self:hide()
!text: tr('Alas! Brave adventurer, you have met a sad fate.\nBut do not despair, for the gods will bring you back\ninto this world in exchange for a small sacrifice\n\nSimply click on Ok to resume your journeys!') @onEscape: self:hide()
width: 550
height: 140 // Main Panel Window
anchors.left: parent.left
MarketTabBar
id: mainTabBar
width: 164
height: 25
anchors.top: parent.top anchors.top: parent.top
margin-left: 10
margin-top: 2
Button
id: buttonOk
!text: tr('Ok')
width: 64
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.bottom
margin-left: 160
Button Panel
id: buttonCancel id: mainTabContent
!text: tr('Cancel') anchors.top: prev.bottom
width: 64 anchors.left: parent.left
anchors.left: prev.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
margin-left: 5 padding: 3
border-width: 1
border-color: #000000

View File

@ -4,7 +4,7 @@ MarketOffer.__index = MarketOffer
local OFFER_TIMESTAMP = 1 local OFFER_TIMESTAMP = 1
local OFFER_COUNTER = 2 local OFFER_COUNTER = 2
MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, state) MarketOffer.new = function(offerId, action, item, amount, price, playerName, state)
local offer = { local offer = {
id = {}, id = {},
action = nil, action = nil,
@ -26,7 +26,11 @@ MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, s
end end
offer.action = action offer.action = action
offer.item = itemId if not item then
g_logger.error('MarketOffer.new - invalid item provided.')
end
offer.item = item
offer.amount = amount offer.amount = amount
offer.price = price offer.price = price
offer.player = playerName offer.player = playerName
@ -67,8 +71,19 @@ function MarketOffer:getId()
return self.id return self.id
end end
function MarketOffer:setAction(action)
if not action or type(action) ~= 'number' then
g_logger.error('MarketOffer.setItem - invalid action id provided.')
end
self.action = action
end
function MarketOffer:getAction()
return self.action
end
function MarketOffer:setItem(item) function MarketOffer:setItem(item)
if not item or type(item) ~= 'number' then if not item or type(item) ~= 'userdata' then
g_logger.error('MarketOffer.setItem - invalid item id provided.') g_logger.error('MarketOffer.setItem - invalid item id provided.')
end end
self.item = item self.item = item

View File

@ -1,11 +1,15 @@
MarketProtocol = {} MarketProtocol = {}
local market
-- private functions -- private functions
local protocol
local function send(msg) local function send(msg)
print(msg:getMessageSize()) if protocol then
g_game.getProtocolGame():safeSend(msg) print(msg:getMessageSize())
--protocol:safeSend(msg)
protocol:send(msg)
end
end end
local function readMarketOffer(msg, action, var) local function readMarketOffer(msg, action, var)
@ -29,12 +33,15 @@ local function readMarketOffer(msg, action, var)
playerName = msg:getString() playerName = msg:getString()
end end
return MarketOffer.new({timestamp, counter}, action, itemId, amount, price, playerName, state) return MarketOffer.new({timestamp, counter}, action, Item.create(itemId), amount, price, playerName, state)
end end
-- parsing protocols -- parsing protocols
local function parseMarketEnter(msg) local function parseMarketEnter(msg)
local balance = msg:getU32() local balance = msg:getU32()
if g_game.getProtocolVersion() < 950 then
msg:getU8() -- get vocation id
end
local offers = msg:getU8() local offers = msg:getU8()
local depotItems = {} local depotItems = {}
@ -47,10 +54,12 @@ local function parseMarketEnter(msg)
end end
Market.onMarketEnter(depotItems, offers, balance) Market.onMarketEnter(depotItems, offers, balance)
return true
end end
local function parseMarketLeave(msg) local function parseMarketLeave(msg)
Market.onMarketLeave() Market.onMarketLeave()
return true
end end
local function parseMarketDetail(msg) local function parseMarketDetail(msg)
@ -59,7 +68,7 @@ local function parseMarketDetail(msg)
local descriptions = {} local descriptions = {}
for i = MarketItemDescription.First, MarketItemDescription.Last do for i = MarketItemDescription.First, MarketItemDescription.Last do
if msg:peekU16() ~= 0x00 then if msg:peekU16() ~= 0x00 then
table.insert(descriptions, {i, msg:getString()}) table.insert(descriptions, {i, msg:getString()}) -- item descriptions
else else
msg:getU16() msg:getU16()
end end
@ -86,6 +95,7 @@ local function parseMarketDetail(msg)
end end
Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats) Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats)
return true
end end
local function parseMarketBrowse(msg) local function parseMarketBrowse(msg)
@ -103,26 +113,55 @@ local function parseMarketBrowse(msg)
end end
Market.onMarketBrowse(offers) Market.onMarketBrowse(offers)
return true
end end
-- public functions -- public functions
function MarketProtocol.init() function MarketProtocol.init()
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter) connect(g_game, { onGameStart = MarketProtocol.registerProtocol,
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave) onGameEnd = MarketProtocol.unregisterProtocol })
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail)
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse) -- reloading module
if g_game.isOnline() then
MarketProtocol.updateProtocol(g_game.getProtocolGame())
end
end end
function MarketProtocol.terminate() function MarketProtocol.terminate()
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter) disconnect(g_game, { onGameStart = MarketProtocol.registerProtocol,
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave) onGameEnd = MarketProtocol.unregisterProtocol })
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail)
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse)
market = nil -- reloading module
if not g_game.isOnline() then
MarketProtocol.updateProtocol(nil)
end
MarketProtocol = nil MarketProtocol = nil
end end
function MarketProtocol.updateProtocol(_protocol)
protocol = _protocol
end
function MarketProtocol.registerProtocol()
if g_game.getFeature(GamePlayerMarket) then
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter)
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave)
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail)
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse)
end
MarketProtocol.updateProtocol(g_game.getProtocolGame())
end
function MarketProtocol.unregisterProtocol()
if g_game.getFeature(GamePlayerMarket) then
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter)
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave)
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail)
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse)
end
MarketProtocol.updateProtocol(nil)
end
-- sending protocols -- sending protocols
function MarketProtocol.sendMarketLeave() function MarketProtocol.sendMarketLeave()

View File

@ -0,0 +1,20 @@
MarketButtonBox < UICheckBox
font: verdana-11px-antialised
color: #ffffffff
size: 106 22
text-offset: 0 0
text-align: center
image-source: /images/tabbutton.png
image-clip: 0 0 20 20
image-border: 2
$hover !disabled:
image-clip: 0 20 20 20
$checked:
image-clip: 0 40 20 20
color: white
$disabled:
color: #666666ff
image-color: #ffffff88

View File

@ -0,0 +1,33 @@
MarketTabBar < UITabBar
size: 80 20
MarketTabBarPanel < Panel
MarketTabBarButton < UIButton
size: 20 25
image-source: /images/tabbutton.png
image-clip: 0 0 20 20
image-border: 2
icon-color: white
color: #aaaaaa
anchors.top: parent.top
padding: 5
$first:
anchors.left: parent.left
$!first:
anchors.left: prev.right
$hover !checked:
image-clip: 0 20 20 20
color: white
$disabled:
image-color: #ffffff66
icon-color: #888888
$checked:
image-clip: 0 20 20 20
color: #ffffff
$on !checked:
color: #f55e5e

View File

@ -0,0 +1,49 @@
Panel
MarketTabBar
id: leftTabBar
width: 107
height:25
anchors.top: parent.top
anchors.left: parent.left
Panel
id: leftTabContent
width: 180
anchors.top: prev.bottom
anchors.left: prev.left
anchors.bottom: parent.bottom
border-width: 1
border-color: #000000
MarketTabBar
id: rightTabBar
width: 157
height:25
anchors.top: parent.top
anchors.right: parent.right
Panel
id: rightTabContent
anchors.top: prev.bottom
anchors.left: leftTabContent.right
anchors.right: prev.right
anchors.bottom: parent.bottom
margin-left:3
border-width: 1
border-color: #000000
Item
id: selectedItem
phantom: true
anchors.top: rightTabBar.bottom
anchors.left: rightTabContent.left
margin-top: 3
margin-left: 3
Label
id: nameLabel
!text: tr('No item selected.')
anchors.top: prev.top
anchors.left: prev.right
margin-left: 5

View File

@ -0,0 +1,125 @@
MarketItemBox < UICheckBox
border-width: 1
border-color: #000000
color: #aaaaaa
text-align: center
text-offset: 0 20
@onCheckChange: Market.onItemBoxChecked(self)
Item
id: item
phantom: true
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 5
$checked:
border-color: #ffffff
$hover !checked:
border-color: #aaaaaa
$disabled:
image-color: #ffffff88
color: #aaaaaa88
Panel
background-color: #22283399
margin: 1
ComboBox
id: filterComboBox
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3
margin-right: 3
margin-left: 3
ComboBox
id: weaponComboBox
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3
margin-right: 3
margin-left: 3
MarketButtonBox
id: filterMatchLevel
checked: false
!text: tr('Level')
!tooltip: tr('Filter list to match your level')
anchors.top: prev.bottom
anchors.left: parent.left
margin-top: 3
margin-right: 3
margin-left: 3
width: 40
height: 20
//@onClick: Market.filterMatchLevel()
MarketButtonBox
id: filterMatchVocation
checked: false
!text: tr('Vocation')
!tooltip: tr('Filter list to match your vocation')
anchors.top: prev.top
anchors.left: prev.right
margin-right: 3
margin-left: 3
width: 60
height: 20
//@onClick: Market.filterMatchVocation()
ComboBox
id: typeComboBox
anchors.top: prev.top
anchors.left: prev.right
anchors.right: parent.right
margin-right: 3
margin-left: 3
MarketButtonBox
id: showDepotOnly
checked: false
!text: tr('Show Depot Only')
!tooltip: tr('Show your depot items only')
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 3
margin-right: 3
margin-left: 3
//@onClick: Market.setDisplayDepot()
Panel
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
margin-top: 10
margin-left: 3
margin-bottom: 10
margin-right: 3
VerticalScrollBar
id: itemsPanelListScrollBar
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
step: 16
pixels-scroll: true
ScrollablePanel
id: itemsPanel
anchors.left: parent.left
anchors.right: prev.left
anchors.top: parent.top
anchors.bottom: parent.bottom
vertical-scrollbar: itemsPanelListScrollBar
layout:
type: grid
cell-size: 34 34
flow: true
auto-spacing: true

View File

@ -0,0 +1,10 @@
Panel
background-color: #22283399
margin: 1
Label
!text: tr('Item Details')
anchors.top: parent.top
anchors.left: parent.left
margin-top: 45
margin-left: 3

View File

@ -0,0 +1,10 @@
Panel
background-color: #22283399
margin: 1
Label
!text: tr('Item Offers')
anchors.top: parent.top
anchors.left: parent.left
margin-top: 45
margin-left: 3

View File

@ -0,0 +1,10 @@
Panel
background-color: #22283399
margin: 1
Label
!text: tr('Item Stats')
anchors.top: parent.top
anchors.left: parent.left
margin-top: 45
margin-left: 3

View File

@ -0,0 +1,9 @@
Panel
background-color: #22283399
margin: 1
Label
!text: tr('Search')
anchors.top: parent.top
anchors.left: parent.left
margin-left: 10

View File

@ -0,0 +1,16 @@
Panel
MarketTabBar
id: offersTabBar
width: 187
height:25
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Panel
id: offersTabContent
anchors.top: prev.bottom
anchors.left: prev.left
anchors.right: prev.right
anchors.bottom: parent.bottom

View File

@ -0,0 +1,9 @@
Panel
background-color: #22283399
margin: 1
Label
!text: tr('Current Offers')
anchors.top: parent.top
anchors.left: parent.left
margin-left: 10

View File

@ -0,0 +1,9 @@
Panel
background-color: #22283399
margin: 1
Label
!text: tr('Item Offers')
anchors.top: parent.top
anchors.left: parent.left
margin-left: 10

View File

@ -0,0 +1,9 @@
Panel
background-color: #22283399
margin: 1
Label
!text: tr('Offer History')
anchors.top: parent.top
anchors.left: parent.left
margin-left: 10

View File

@ -150,14 +150,35 @@ function Outfit.create(creatureOutfit, outfitList, creatureMount, mountList)
mountCreature = creatureMount mountCreature = creatureMount
outfits = outfitList outfits = outfitList
mounts = mountList mounts = mountList
Outfit.destroy() Outfit.destroy()
outfitWindow = g_ui.displayUI('outfitwindow.otui') outfitWindow = g_ui.displayUI('outfitwindow.otui')
outfit = outfitCreature:getOutfit() local colorBoxPanel = outfitWindow:getChildById('colorBoxPanel')
if mountCreature then
-- setup outfit/mount display boxs
local outfitCreatureBox = outfitWindow:getChildById('outfitCreatureBox')
if outfitCreature then
outfit = outfitCreature:getOutfit()
outfitCreatureBox:setCreature(outfitCreature)
else
outfitCreatureBox:hide()
outfitWindow:getChildById('outfitName'):hide()
outfitWindow:getChildById('outfitNextButton'):hide()
outfitWindow:getChildById('outfitPrevButton'):hide()
end
local mountCreatureBox = outfitWindow:getChildById('mountCreatureBox')
if mountCreature then
mount = mountCreature:getOutfit() mount = mountCreature:getOutfit()
mountCreatureBox:setCreature(mountCreature)
else
mountCreatureBox:hide()
outfitWindow:getChildById('mountName'):hide()
outfitWindow:getChildById('mountNextButton'):hide()
outfitWindow:getChildById('mountPrevButton'):hide()
end end
-- set addons
addons = { addons = {
[1] = {widget = outfitWindow:getChildById('addon1'), value = 1}, [1] = {widget = outfitWindow:getChildById('addon1'), value = 1},
[2] = {widget = outfitWindow:getChildById('addon2'), value = 2}, [2] = {widget = outfitWindow:getChildById('addon2'), value = 2},
@ -174,21 +195,14 @@ function Outfit.create(creatureOutfit, outfitList, creatureMount, mountList)
end end
end end
-- hook outfit sections
currentClotheButtonBox = outfitWindow:getChildById('head') currentClotheButtonBox = outfitWindow:getChildById('head')
outfitWindow:getChildById('head').onCheckChange = onClotheCheckChange outfitWindow:getChildById('head').onCheckChange = onClotheCheckChange
outfitWindow:getChildById('primary').onCheckChange = onClotheCheckChange outfitWindow:getChildById('primary').onCheckChange = onClotheCheckChange
outfitWindow:getChildById('secondary').onCheckChange = onClotheCheckChange outfitWindow:getChildById('secondary').onCheckChange = onClotheCheckChange
outfitWindow:getChildById('detail').onCheckChange = onClotheCheckChange outfitWindow:getChildById('detail').onCheckChange = onClotheCheckChange
local outfitCreatureBox = outfitWindow:getChildById('outfitCreatureBox') -- populate color panel
local colorBoxPanel = outfitWindow:getChildById('colorBoxPanel')
outfitCreatureBox:setCreature(outfitCreature)
if mountCreature then
local mountCreatureBox = outfitWindow:getChildById('mountCreatureBox')
mountCreatureBox:setCreature(mountCreature)
end
for j=0,6 do for j=0,6 do
for i=0,18 do for i=0,18 do
local colorBox = g_ui.createWidget('ColorBox', colorBoxPanel) local colorBox = g_ui.createWidget('ColorBox', colorBoxPanel)
@ -206,9 +220,10 @@ function Outfit.create(creatureOutfit, outfitList, creatureMount, mountList)
end end
end end
-- set current outfit/mount
currentOutfit = 1 currentOutfit = 1
for i=1,#outfitList do for i=1,#outfitList do
if outfitList[i][1] == outfit.type then if outfit and outfitList[i][1] == outfit.type then
currentOutfit = i currentOutfit = i
break break
end end

View File

@ -48,7 +48,7 @@ Window
Label Label
id: outfitName id: outfitName
!text: tr('No Outfit') !text: tr('No Outfit')
width: 100 width: 115
anchors.bottom: prev.top anchors.bottom: prev.top
anchors.left: prev.left anchors.left: prev.left
margin-bottom: 2 margin-bottom: 2
@ -81,7 +81,7 @@ Window
Label Label
id: mountName id: mountName
!text: tr('No Mount') !text: tr('No Mount')
width: 140 width: 115
anchors.bottom: prev.top anchors.bottom: prev.top
anchors.left: prev.left anchors.left: prev.left
margin-bottom: 2 margin-bottom: 2
@ -95,7 +95,7 @@ Window
@onClick: Outfit.nextMountType() @onClick: Outfit.nextMountType()
PrevMountButton PrevMountButton
id: mountPreviousButton id: mountPrevButton
anchors.right: mountCreatureBox.left anchors.right: mountCreatureBox.left
anchors.verticalCenter: mountCreatureBox.verticalCenter anchors.verticalCenter: mountCreatureBox.verticalCenter
margin-right: 3 margin-right: 3
@ -170,7 +170,7 @@ Window
anchors.left: head.left anchors.left: head.left
margin-top: 3 margin-top: 3
margin-right: 20 margin-right: 20
width: 323 width: 302
height: 119 height: 119
layout: layout:
type: grid type: grid

View File

@ -1,11 +1,15 @@
PlayerMount = {} PlayerMount = {}
function PlayerMount.init() function PlayerMount.init()
g_keyboard.bindKeyDown('Ctrl+R', PlayerMount.toggleMount, gameRootPanel) if g_game.getFeature(GamePlayerMount) then
g_keyboard.bindKeyDown('Ctrl+R', PlayerMount.toggleMount, gameRootPanel)
end
end end
function PlayerMount.terminate() function PlayerMount.terminate()
g_keyboard.unbindKeyDown('Ctrl+R', gameRootPanel) if g_game.getFeature(GamePlayerMount) then
g_keyboard.unbindKeyDown('Ctrl+R', gameRootPanel)
end
PlayerMount = nil PlayerMount = nil
end end

View File

@ -31,8 +31,7 @@ MarketItemDescription = {
Ability = 12, Ability = 12,
Charges = 13, Charges = 13,
WeaponName = 14, WeaponName = 14,
Weight = 15, Weight = 15
First = Armor,
Last = Weight
} }
MarketItemDescription.First = MarketItemDescription.Armor
MarketItemDescription.Last = MarketItemDescription.Weight

View File

@ -1074,7 +1074,7 @@ bool Game::checkBotProtection()
// accepts calls comming from a stacktrace containing only C++ functions, // accepts calls comming from a stacktrace containing only C++ functions,
// if the stacktrace contains a lua function, then only accept if the engine is processing an input event // if the stacktrace contains a lua function, then only accept if the engine is processing an input event
if(m_denyBotCall && g_lua.isInCppCallback() && !g_app.isOnInputEvent()) { if(m_denyBotCall && g_lua.isInCppCallback() && !g_app.isOnInputEvent()) {
g_logger.error(g_lua.traceback("caught a lua call to a bot protected game function, the call was canceled")); g_logger.error(g_lua.traceback("caught a lua call to a bot protected game function, the call was cancelled"));
return false; return false;
} }
#endif #endif

View File

@ -274,7 +274,9 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassMemberFunction<Thing>("isHookSouth", &Thing::isHookSouth); g_lua.bindClassMemberFunction<Thing>("isHookSouth", &Thing::isHookSouth);
g_lua.bindClassMemberFunction<Thing>("isTranslucent", &Thing::isTranslucent); g_lua.bindClassMemberFunction<Thing>("isTranslucent", &Thing::isTranslucent);
g_lua.bindClassMemberFunction<Thing>("isFullGround", &Thing::isFullGround); g_lua.bindClassMemberFunction<Thing>("isFullGround", &Thing::isFullGround);
g_lua.bindClassMemberFunction<Thing>("isMarketable", &Thing::isMarketable);
g_lua.bindClassMemberFunction<Thing>("getParentContainer", &Thing::getParentContainer); g_lua.bindClassMemberFunction<Thing>("getParentContainer", &Thing::getParentContainer);
g_lua.bindClassMemberFunction<Thing>("getMarketData", &Thing::getMarketData);
g_lua.registerClass<House>(); g_lua.registerClass<House>();
g_lua.bindClassStaticFunction<House>("create", []{ return HousePtr(new House); }); g_lua.bindClassStaticFunction<House>("create", []{ return HousePtr(new House); });
@ -334,6 +336,8 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassMemberFunction<Item>("getCount", &Item::getCount); g_lua.bindClassMemberFunction<Item>("getCount", &Item::getCount);
g_lua.bindClassMemberFunction<Item>("getId", &Item::getId); g_lua.bindClassMemberFunction<Item>("getId", &Item::getId);
g_lua.bindClassMemberFunction<Item>("isStackable", &Item::isStackable); g_lua.bindClassMemberFunction<Item>("isStackable", &Item::isStackable);
g_lua.bindClassMemberFunction<Item>("isMarketable", &Item::isMarketable);
g_lua.bindClassMemberFunction<Item>("getMarketData", &Item::isMarketable);
g_lua.registerClass<Effect, Thing>(); g_lua.registerClass<Effect, Thing>();
g_lua.registerClass<Missile, Thing>(); g_lua.registerClass<Missile, Thing>();

View File

@ -97,3 +97,41 @@ bool luavalue_cast(int index, Position& pos)
} }
return false; return false;
} }
int push_luavalue(const MarketData& data)
{
g_lua.newTable();
g_lua.pushInteger(data.category);
g_lua.setField("category");
g_lua.pushString(data.name);
g_lua.setField("name");
g_lua.pushInteger(data.requiredLevel);
g_lua.setField("requiredLevel");
g_lua.pushInteger(data.restrictProfession);
g_lua.setField("restrictProfession");
g_lua.pushInteger(data.showAs);
g_lua.setField("showAs");
g_lua.pushInteger(data.tradeAs);
g_lua.setField("tradeAs");
return 1;
}
bool luavalue_cast(int index, MarketData& data)
{
if(g_lua.isTable(index)) {
g_lua.getField("category", index);
data.category = g_lua.popInteger();
g_lua.getField("name", index);
data.name = g_lua.popString();
g_lua.getField("requiredLevel", index);
data.requiredLevel = g_lua.popInteger();
g_lua.getField("restrictProfession", index);
data.restrictProfession = g_lua.popInteger();
g_lua.getField("showAs", index);
data.showAs = g_lua.popInteger();
g_lua.getField("tradeAs", index);
data.tradeAs = g_lua.popInteger();
return true;
}
return false;
}

View File

@ -36,4 +36,8 @@ bool luavalue_cast(int index, Outfit& outfit);
int push_luavalue(const Position& pos); int push_luavalue(const Position& pos);
bool luavalue_cast(int index, Position& pos); bool luavalue_cast(int index, Position& pos);
// market
int push_luavalue(const MarketData& data);
bool luavalue_cast(int index, MarketData& data);
#endif #endif

View File

@ -128,8 +128,10 @@ public:
bool isFullGround() { return rawGetDatType()->isFullGround(); } bool isFullGround() { return rawGetDatType()->isFullGround(); }
bool isIgnoreLook() { return rawGetDatType()->isIgnoreLook(); } bool isIgnoreLook() { return rawGetDatType()->isIgnoreLook(); }
bool isCloth() { return rawGetDatType()->isCloth(); } bool isCloth() { return rawGetDatType()->isCloth(); }
bool isMarketable() { return rawGetDatType()->isMarketable(); }
MarketData getMarketData() { return rawGetDatType()->getMarketData(); } MarketData getMarketData() { return rawGetDatType()->getMarketData(); }
protected: protected:
Position m_position; Position m_position;
uint16 m_datId; uint16 m_datId;

View File

@ -172,6 +172,7 @@ public:
bool isFullGround() { return m_attribs.has(DatAttribFullGround); } bool isFullGround() { return m_attribs.has(DatAttribFullGround); }
bool isIgnoreLook() { return m_attribs.has(DatAttribIgnoreLook); } bool isIgnoreLook() { return m_attribs.has(DatAttribIgnoreLook); }
bool isCloth() { return m_attribs.has(DatAttribCloth); } bool isCloth() { return m_attribs.has(DatAttribCloth); }
bool isMarketable() { return m_attribs.has(DatAttribMarket); }
private: private:
const TexturePtr& getTexture(int animationPhase); const TexturePtr& getTexture(int animationPhase);

View File

@ -48,8 +48,8 @@ public:
const ThingTypeDatPtr& getDatType(uint16 id, DatCategory category); const ThingTypeDatPtr& getDatType(uint16 id, DatCategory category);
const ThingTypeOtbPtr& getOtbType(uint16 id); const ThingTypeOtbPtr& getOtbType(uint16 id);
ThingTypeDat *rawGetDatType(uint16 id, DatCategory category) { return m_datTypes[category][id].get(); } ThingTypeDat* rawGetDatType(uint16 id, DatCategory category) { return m_datTypes[category][id].get(); }
ThingTypeOtb *rawGetOtbType(uint16 id) { return m_otbTypes[id].get(); } ThingTypeOtb* rawGetOtbType(uint16 id) { return m_otbTypes[id].get(); }
uint32 getDatSignature() { return m_datSignature; } uint32 getDatSignature() { return m_datSignature; }
uint32 getOtbMajorVersion() { return m_otbMajorVersion; } uint32 getOtbMajorVersion() { return m_otbMajorVersion; }