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

@@ -1,61 +1,262 @@
Market = {}
g_ui.importStyle('market.otui')
g_ui.importStyle('ui/general/markettabs.otui')
g_ui.importStyle('ui/general/marketbuttons.otui')
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()
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
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
end
function Market.onMarketEnter(depotItems, offers, balance)
-- open market window
-- populate market?
print('onMarketEnter')
print(offers)
print(balance)
print('depotItems:')
for k, item in pairs(depotItems) do
print('id- '..item[1])
print('count- '..item[2])
function Market.updateOffers(offers)
for k, offer in pairs(offers) do
if offer and offer:getAction() == MarketAction.Buy then
table.insert(marketOffers[MarketAction.Buy], offer)
else
table.insert(marketOffers[MarketAction.Sell], offer)
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
function Market.onMarketLeave()
-- close market window?
print('onMarketLeave')
marketWindow:hide()
end
function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats)
-- populate market widget
print('onMarketDetail')
print(itemId)
Market.updateDetails(itemId, descriptions, purchaseStats, saleStats)
print('')
print('[onMarketDetail]')
print('itemId: '..itemId)
print('descriptions:')
for k, desc in pairs(descriptions) do
print('type- '..desc[1])
print('description- '..desc[2])
print(' type: '..desc[1]..' | description: '..desc[2])
end
print('purchaseStats:')
for k, stat in pairs(purchaseStats) do
print('transactions- '..stat[1])
print('total price- '..stat[2])
print('highest price- '..stat[3])
print('lowest price- '..stat[4])
print(' transactions: '..stat[1])
print(' total price: '..stat[2])
print(' highest price: '..stat[3])
print(' lowest price: '..stat[4])
end
print('saleStats:')
for k, stat in pairs(saleStats) do
print('transactions- '..stat[1])
print('total price- '..stat[2])
print('highest price- '..stat[3])
print('lowest price- '..stat[4])
print(' transactions: '..stat[1])
print(' total price: '..stat[2])
print(' highest price: '..stat[3])
print(' lowest price: '..stat[4])
end
end
function Market.onMarketBrowse(offers)
-- populate market widget
print('onMarketBrowse')
Market.updateOffers(offers)
end
function Market.onItemBoxChecked(widget)
if widget:isChecked() then
Market.updateSelectedItem(widget.item)
end
end

View File

@@ -1,29 +1,26 @@
MarketWindow < MainWindow
id: marketWindow
!text: tr('Market')
size: 350 155
size: 680 460
Label
!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!')
width: 550
height: 140
anchors.left: parent.left
@onEnter: self:hide()
@onEscape: self:hide()
// Main Panel Window
MarketTabBar
id: mainTabBar
width: 164
height: 25
anchors.top: parent.top
margin-left: 10
margin-top: 2
Button
id: buttonOk
!text: tr('Ok')
width: 64
anchors.left: parent.left
anchors.bottom: parent.bottom
margin-left: 160
Button
id: buttonCancel
!text: tr('Cancel')
width: 64
anchors.left: prev.right
Panel
id: mainTabContent
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
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_COUNTER = 2
MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, state)
MarketOffer.new = function(offerId, action, item, amount, price, playerName, state)
local offer = {
id = {},
action = nil,
@@ -26,7 +26,11 @@ MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, s
end
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.price = price
offer.player = playerName
@@ -67,8 +71,19 @@ function MarketOffer:getId()
return self.id
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)
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.')
end
self.item = item

View File

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