More market work (getting close to completion)

* Can now create market offers with fully working UI.
* All filtering is now completed (just need to finish word searching).
* Added some user friendly features to offer selections and item displays (show amount in depot).
* Some more UI ascetics.
* Some other minor market fixes.

TODO:
* Finishing applying changes for latest module updates by edubart.
* Finish buying/selling existing offers.
* Word searching items.
* Offer management.
* Full cipsoft tibia testing.
master
BeniS 12 years ago
parent 2b2f5b33ff
commit 7aba117cf2

@ -1,96 +1,61 @@
Market = {}
g_ui.importStyle('market.otui')
g_ui.importStyle('ui/general/markettabs.otui')
g_ui.importStyle('ui/general/marketbuttons.otui')
g_ui.importStyle('ui/general/marketcombobox.otui')
local marketWindow
local mainTabBar
local marketOffersPanel
local selectionTabBar
local displaysTabBar
local offersTabBar
local itemsPanel
local browsePanel
local searchPanel
local itemOffersPanel
local itemDetailsPanel
local itemStatsPanel
local myOffersPanel
local currentOffersPanel
local offerHistoryPanel
local selectedItem
local nameLabel
local radioItemSet
local categoryList
local subCategoryList
local slotFilterList
local filterButtons = {}
local buyOfferTable
local sellOfferTable
local detailsTable
local buyStatsTable
local sellStatsTable
local marketOffers = {}
local marketItems = {}
local depot = {}
local information = {}
local currentItems = {}
local protocol = runinsandbox('marketprotocol.lua')
marketWindow = nil
mainTabBar = nil
displaysTabBar = nil
offersTabBar = nil
selectionTabBar = nil
marketOffersPanel = nil
browsePanel = nil
searchPanel = nil
itemOffersPanel = nil
itemDetailsPanel = nil
itemStatsPanel = nil
myOffersPanel = nil
currentOffersPanel = nil
offerHistoryPanel = nil
itemsPanel = nil
selectedOffer = {}
nameLabel = nil
feeLabel = nil
totalPriceEdit = nil
piecePriceEdit = nil
amountEdit = nil
radioItemSet = nil
selectedItem = nil
offerTypeList = nil
categoryList = nil
subCategoryList = nil
slotFilterList = nil
createOfferButton = nil
anonymous = nil
filterButtons = {}
buyOfferTable = nil
sellOfferTable = nil
detailsTable = nil
buyStatsTable = nil
sellStatsTable = nil
marketOffers = {}
marketItems = {}
information = {}
currentItems = {}
fee = 0
local offerTableHeader = {
{['text'] = 'Player Name', ['width'] = 100},
{['text'] = 'Amount', ['width'] = 60},
{['text'] = 'Total Price', ['width'] = 90},
{['text'] = 'Peice Price', ['width'] = 80},
{['text'] = 'Piece Price', ['width'] = 80},
{['text'] = 'Ends at', ['width'] = 120}
}
local function getMarketCategoryName(id)
if table.hasKey(MarketCategoryStrings, id) then
return MarketCategoryStrings[id]
end
end
local function getMarketCategoryId(name)
local id = table.find(MarketCategoryStrings, name)
if id then
return id
end
end
local function getMarketDescriptionName(id)
if table.hasKey(MarketItemDescriptionStrings, id) then
return MarketItemDescriptionStrings[id]
end
end
local function getMarketDescriptionId(name)
local id = table.find(MarketItemDescriptionStrings, name)
if id then
return id
end
end
}
local function getMarketSlotFilterId(name)
local id = table.find(MarketSlotFilters, name)
if id then
return id
end
end
local function getMarketSlotFilterName(id)
if table.hasKey(MarketSlotFilters, id) then
return MarketSlotFilters[id]
end
end
local function isValidItem(item, category)
local function isItemValid(item, category)
if item.marketData.category ~= category and category ~= MarketCategory[0] then
return false
end
@ -121,76 +86,218 @@ local function isValidItem(item, category)
return false
end
end
if filterDepot and not Market.depotContains(item.ptr:getId()) then
if filterDepot and Market.depotContains(item.ptr:getId()) <= 0 then
return false
end
return true
end
local function clearSelectedItem()
if selectedItem and selectedItem.item.ptr then
Market.updateOffers({})
radioItemSet:selectWidget(nil)
nameLabel:setText('No item selected.')
local function clearItems()
currentItems = {}
Market.refreshItemsWidget()
end
selectedItem:setItem(nil)
selectedItem.item = {}
local function clearFilters()
for _, filter in pairs(filterButtons) do
if filter and filter:isChecked() then
filter:setChecked(false)
end
end
end
detailsTable:clearData()
buyStatsTable:clearData()
sellStatsTable:clearData()
local function refreshTypeList()
offerTypeList:clearOptions()
offerTypeList:addOption('Buy')
if Market.isItemSelected() then
if Market.depotContains(selectedItem.item.ptr:getId()) > 0 then
offerTypeList:addOption('Sell')
end
end
end
local function initMarketItems()
-- populate all market items
marketItems = {}
local types = g_things.findThingTypeByAttr(ThingAttrMarket)
for i = 1, #types do
local t = types[i]
local newItem = Item.create(t:getId())
if newItem then
local marketData = t:getMarketData()
if not table.empty(marketData) then
local item = {
ptr = newItem,
marketData = marketData
local function refreshFee()
feeLabel:setText('')
fee = 0
end
local function updateOffers(offers)
marketOffers[MarketAction.Buy] = {}
marketOffers[MarketAction.Sell] = {}
if not buyOfferTable or not sellOfferTable then
return
end
buyOfferTable:clearData()
sellOfferTable:clearData()
balanceLabel:setColor('#bbbbbb')
for k, offer in pairs(offers) do
if offer and offer:getAction() == MarketAction.Buy then
local data = {
{['text'] = offer:getPlayer(), ['width'] = 100},
{['text'] = offer:getAmount(), ['width'] = 60},
{['text'] = offer:getPrice()*offer:getAmount(), ['width'] = 90},
{['text'] = offer:getPrice(), ['width'] = 80},
{['text'] = string.gsub(os.date('%c', offer:getTimeStamp()), " ", " "), ['width'] = 120}
}
marketItems[#marketItems+1] = item
buyOfferTable:addRow(data, offer:getId())
table.insert(marketOffers[MarketAction.Buy], offer)
else
local data = {
{['text'] = offer:getPlayer(), ['width'] = 100},
{['text'] = offer:getAmount(), ['width'] = 60},
{['text'] = offer:getPrice()*offer:getAmount(), ['width'] = 90},
{['text'] = offer:getPrice(), ['width'] = 80},
{['text'] = string.gsub(os.date('%c', offer:getTimeStamp()), " ", " "), ['width'] = 120}
}
sellOfferTable:addRow(data, offer:getId())
table.insert(marketOffers[MarketAction.Sell], offer)
end
end
end
local function updateDetails(itemId, descriptions, purchaseStats, saleStats)
if not selectedItem then
return
end
selectedItem.item.details = {
descriptions = descriptions,
purchaseStats = purchaseStats,
saleStats = saleStats
}
-- update item details
detailsTable:clearData()
for k, desc in pairs(descriptions) do
local columns = {
{['text'] = getMarketDescriptionName(desc[1])..':'},
{['text'] = desc[2], ['width'] = 330}
}
detailsTable:addRow(columns)
end
-- update sale item statistics
sellStatsTable:clearData()
if table.empty(saleStats) then
sellStatsTable:addRow({{['text'] = 'No information'}})
else
for k, stat in pairs(saleStats) do
if not table.empty(stat) then
sellStatsTable:addRow({{['text'] = 'Total Transations:'},
{['text'] = stat[1], ['width'] = 270}})
sellStatsTable:addRow({{['text'] = 'Highest Price:'},
{['text'] = stat[3], ['width'] = 270}})
sellStatsTable:addRow({{['text'] = 'Average Price:'},
{['text'] = math.floor(stat[2]/stat[1])}})
sellStatsTable:addRow({{['text'] = 'Lowest Price:'},
{['text'] = stat[4], ['width'] = 270}})
end
end
end
-- update buy item statistics
buyStatsTable:clearData()
if table.empty(purchaseStats) then
buyStatsTable:addRow({{['text'] = 'No information'}})
else
for k, stat in pairs(purchaseStats) do
if not table.empty(stat) then
buyStatsTable:addRow({{['text'] = 'Total Transations:'},
{['text'] = stat[1], ['width'] = 270}})
buyStatsTable:addRow({{['text'] = 'Highest Price:'},
{['text'] = stat[3], ['width'] = 270}})
buyStatsTable:addRow({{['text'] = 'Average Price:'},
{['text'] = math.floor(stat[2]/stat[1]), ['width'] = 270}})
buyStatsTable:addRow({{['text'] = 'Lowest Price:'},
{['text'] = stat[4], ['width'] = 270}})
end
end
end
end
local function updateItemsWidget()
itemsPanel = browsePanel:recursiveGetChildById('itemsPanel')
local layout = itemsPanel:getLayout()
layout:disableUpdates()
local function updateSelectedItem(newItem)
selectedItem.item = newItem
clearSelectedItem()
itemsPanel:destroyChildren()
Market.resetCreateOffer()
if Market.isItemSelected() then
selectedItem:setItem(selectedItem.item.ptr)
nameLabel:setText(selectedItem.item.marketData.name)
-- update offer types
Market.enableCreateOffer(true)
if radioItemSet then
radioItemSet:destroy()
MarketProtocol.sendMarketBrowse(selectedItem.item.ptr:getId()) -- send browsed msg
else
Market.Market.clearSelectedItem()
end
radioItemSet = UIRadioGroup.create()
end
for i = 1, #currentItems do
local item = currentItems[i]
local itemBox = g_ui.createWidget('MarketItemBox', itemsPanel)
local itemWidget = itemBox:getChildById('item')
local function updateBalance(balance)
local balance = tonumber(balance)
if not balance then
return
end
itemBox.item = item
itemWidget:setItem(item.ptr)
if balance < 0 then balance = 0 end
information.balance = balance
radioItemSet:addWidget(itemBox)
balanceLabel = marketWindow:recursiveGetChildById('balanceLabel')
balanceLabel:setText('Balance: '..balance..'gp')
balanceLabel:resizeToText()
end
local function updateFee(price, amount)
fee = math.ceil(price / 100 * amount)
if fee < 20 then
fee = 20
elseif fee > 1000 then
fee = 1000
end
feeLabel:setText('Fee: '..fee)
feeLabel:resizeToText()
end
layout:enableUpdates()
layout:update()
local function onSelectSellOffer(table, selectedRow, previousSelectedRow)
updateBalance()
for _, offer in pairs(marketOffers[MarketAction.Sell]) do
if offer:isEqual(selectedRow.ref) then
selectedOffer[MarketAction.Sell] = offer
end
end
local offer = selectedOffer[MarketAction.Sell]
if offer then
if offer:getPrice() > information.balance then
balanceLabel:setColor('#b22222')
else
local slice = (information.balance / 2)
if (offer:getPrice()/slice) * 100 <= 40 then
color = '#008b00' -- green
elseif (offer:getPrice()/slice) * 100 <= 70 then
color = '#eec900' -- yellow
else
color = '#ee9a00' -- orange
end
balanceLabel:setColor(color)
end
end
end
local function onUpdateCategory(combobox, option)
local function onSelectBuyOffer(table, selectedRow, previousSelectedRow)
updateBalance()
for _, offer in pairs(marketOffers[MarketAction.Buy]) do
if offer:isEqual(selectedRow.ref) then
selectedOffer[MarketAction.Buy] = offer
end
end
end
local function onChangeCategory(combobox, option)
local id = getMarketCategoryId(option)
if id == MarketCategory.MetaWeapons then
-- enable and load weapons filter/items
@ -205,7 +312,7 @@ local function onUpdateCategory(combobox, option)
end
end
local function onUpdateSubCategory(combobox, option)
local function onChangeSubCategory(combobox, option)
local id = getMarketCategoryId(option)
Market.loadMarketItems(id)
-- setup slot filter
@ -220,10 +327,74 @@ local function onUpdateSubCategory(combobox, option)
slotFilterList:setEnabled(true)
end
local function onUpdateSlotFilter(combobox, option)
local function onChangeSlotFilter(combobox, option)
Market.updateCurrentItems()
end
local function onChangeOfferType(combobox, option)
local id = selectedItem.item.ptr:getId()
if option == 'Sell' then
local max = Market.depotContains(id)
amountEdit:setMaximum(max)
else
amountEdit:setMaximum(999999)
end
end
local function onTotalPriceChange()
local totalPrice = totalPriceEdit:getValue()
local piecePrice = piecePriceEdit:getValue()
local amount = amountEdit:getValue()
piecePriceEdit:setValue(math.floor(totalPrice/amount))
if Market.isItemSelected() then
updateFee(totalPrice, amount)
end
end
local function onPiecePriceChange()
local totalPrice = totalPriceEdit:getValue()
local piecePrice = piecePriceEdit:getValue()
local amount = amountEdit:getValue()
totalPriceEdit:setValue(piecePrice*amount)
if Market.isItemSelected() then
updateFee(totalPrice, amount)
end
end
local function onAmountChange()
local totalPrice = totalPriceEdit:getValue()
local piecePrice = piecePriceEdit:getValue()
local amount = amountEdit:getValue()
piecePriceEdit:setValue(math.floor(totalPrice/amount))
totalPriceEdit:setValue(piecePrice*amount)
if Market.isItemSelected() then
updateFee(totalPrice, amount)
end
end
local function initMarketItems()
-- populate all market items
marketItems = {}
local types = g_things.findThingTypeByAttr(ThingAttrMarket)
for i = 1, #types do
local t = types[i]
local newItem = Item.create(t:getId())
if newItem then
local marketData = t:getMarketData()
if not table.empty(marketData) then
local item = {
ptr = newItem,
marketData = marketData
}
marketItems[#marketItems+1] = item
end
end
end
end
local function initInterface()
-- TODO: clean this up
-- setup main tabs
@ -269,10 +440,27 @@ local function initInterface()
offersTabBar:addTab(tr('Offer History'), offerHistoryPanel)
-- setup selected item
nameLabel = marketOffersPanel:recursiveGetChildById('nameLabel')
selectedItem = marketOffersPanel:recursiveGetChildById('selectedItem')
nameLabel = marketOffersPanel:getChildById('nameLabel')
selectedItem = marketOffersPanel:getChildById('selectedItem')
selectedItem.item = {}
-- setup create new offer
totalPriceEdit = marketOffersPanel:getChildById('totalPriceEdit')
piecePriceEdit = marketOffersPanel:getChildById('piecePriceEdit')
amountEdit = marketOffersPanel:getChildById('amountEdit')
feeLabel = marketOffersPanel:getChildById('feeLabel')
totalPriceEdit.onValueChange = onTotalPriceChange
piecePriceEdit.onValueChange = onPiecePriceChange
amountEdit.onValueChange = onAmountChange
offerTypeList = marketOffersPanel:getChildById('offerTypeComboBox')
offerTypeList.onOptionChange = onChangeOfferType
anonymous = marketOffersPanel:getChildById('anonymousCheckBox')
createOfferButton = marketOffersPanel:getChildById('createOfferButton')
createOfferButton.onClick = Market.createNewOffer
Market.enableCreateOffer(false)
-- setup filters
filterButtons[MarketFilters.Vocation] = browsePanel:getChildById('filterVocation')
filterButtons[MarketFilters.Level] = browsePanel:getChildById('filterLevel')
@ -297,9 +485,9 @@ local function initInterface()
subCategoryList:setEnabled(false)
-- hook item filters
categoryList.onOptionChange = onUpdateCategory
subCategoryList.onOptionChange = onUpdateSubCategory
slotFilterList.onOptionChange = onUpdateSlotFilter
categoryList.onOptionChange = onChangeCategory
subCategoryList.onOptionChange = onChangeSubCategory
slotFilterList.onOptionChange = onChangeSlotFilter
-- get tables
buyOfferTable = itemOffersPanel:recursiveGetChildById('buyingTable')
@ -307,9 +495,18 @@ local function initInterface()
detailsTable = itemDetailsPanel:recursiveGetChildById('detailsTable')
buyStatsTable = itemStatsPanel:recursiveGetChildById('buyStatsTable')
sellStatsTable = itemStatsPanel:recursiveGetChildById('sellStatsTable')
buyOfferTable.onSelectionChange = onSelectBuyOffer
sellOfferTable.onSelectionChange = onSelectSellOffer
end
function Market.init()
function init()
g_ui.importStyle('market.otui')
g_ui.importStyle('ui/general/markettabs.otui')
g_ui.importStyle('ui/general/marketbuttons.otui')
g_ui.importStyle('ui/general/marketcombobox.otui')
protocol.initProtocol()
connect(g_game, { onGameEnd = Market.reset })
marketWindow = g_ui.createWidget('MarketWindow', rootWidget)
marketWindow:hide()
@ -317,58 +514,140 @@ function Market.init()
initMarketItems()
end
function Market.terminate()
function terminate()
protocol.terminateProtocol()
disconnect(g_game, { onGameEnd = Market.reset })
if marketWindow then
marketWindow:destroy()
marketWindow = nil
end
mainTabBar = nil
displaysTabBar = nil
offersTabBar = nil
selectionTabBar = nil
marketOffersPanel = nil
browsePanel = nil
searchPanel = nil
itemOffersPanel = nil
itemDetailsPanel = nil
itemStatsPanel = nil
myOffersPanel = nil
currentOffersPanel = nil
offerHistoryPanel = nil
itemsPanel = nil
nameLabel = nil
radioItemSet = nil
selectedItem = nil
categoryList = nil
subCategoryList = nil
slotFilterList = nil
filterButtons = {}
buyOfferTable = nil
sellOfferTable = nil
detailsTable = nil
buyStatsTable = nil
sellStatsTable = nil
marketOffers = {}
marketItems = {}
information = {}
currentItems = {}
end
Market = nil
end
function Market.reset()
categoryList:setCurrentOption(getMarketCategoryName(MarketCategory.First))
Market.clearSelectedItem()
clearFilters()
clearItems()
end
function Market.clearSelectedItem()
if selectedItem and selectedItem.item.ptr then
Market.resetCreateOffer()
offerTypeList:clearOptions()
offerTypeList:setText('Please Select')
offerTypeList:setEnabled(false)
updateOffers({})
radioItemSet:selectWidget(nil)
nameLabel:setText('No item selected.')
selectedItem:setItem(nil)
selectedItem.item = {}
detailsTable:clearData()
buyStatsTable:clearData()
sellStatsTable:clearData()
Market.enableCreateOffer(false)
end
end
function Market.isItemSelected()
return selectedItem and not table.empty(selectedItem.item) and selectedItem.item.ptr
end
function Market.depotContains(itemId)
local count = 0
for i = 1, #information.depotItems do
local item = information.depotItems[i]
if item.ptr:getId() == itemId then
return true
count = count + item.ptr:getCount()
end
end
return false
return count
end
function Market.enableCreateOffer(enable)
offerTypeList:setEnabled(enable)
totalPriceEdit:setEnabled(enable)
piecePriceEdit:setEnabled(enable)
amountEdit:setEnabled(enable)
anonymous:setEnabled(enable)
createOfferButton:setEnabled(enable)
local prevAmountButton = marketOffersPanel:recursiveGetChildById('prevAmountButton')
local nextAmountButton = marketOffersPanel:recursiveGetChildById('nextAmountButton')
prevAmountButton:setEnabled(enable)
nextAmountButton:setEnabled(enable)
end
function Market.incrementAmount()
amountEdit:setValue(amountEdit:getValue() + 1)
-- change total price/piece price according
end
function Market.decrementAmount()
amountEdit:setValue(amountEdit:getValue() - 1)
-- change total price/piece price according
end
function Market.updateCurrentItems()
local id = getMarketCategoryId(categoryList:getCurrentOption().text)
if id == MarketCategory.MetaWeapons then
id = getMarketCategoryId(subCategoryList:getCurrentOption().text)
end
Market.loadMarketItems(id)
end
function Market.resetCreateOffer()
piecePriceEdit:setValue(1)
totalPriceEdit:setValue(1)
amountEdit:setValue(1)
refreshTypeList()
refreshFee()
end
function Market.refreshItemsWidget(selectItem)
local selectItem = selectItem or 0
itemsPanel = browsePanel:recursiveGetChildById('itemsPanel')
local layout = itemsPanel:getLayout()
layout:disableUpdates()
Market.clearSelectedItem()
itemsPanel:destroyChildren()
if radioItemSet then
radioItemSet:destroy()
end
radioItemSet = UIRadioGroup.create()
local select = nil
for i = 1, #currentItems do
local item = currentItems[i]
local itemBox = g_ui.createWidget('MarketItemBox', itemsPanel)
itemBox.onCheckChange = Market.onItemBoxChecked
itemBox.item = item
if selectItem > 0 and item.ptr:getId() == selectItem then
select = itemBox
end
local itemWidget = itemBox:getChildById('item')
itemWidget:setItem(item.ptr)
local amount = Market.depotContains(item.ptr:getId())
if amount > 0 then
itemWidget:setText(amount)
itemBox:setTooltip('You have '.. amount ..' in your depot.')
end
radioItemSet:addWidget(itemBox)
end
if select then
select:setChecked(true)
end
layout:enableUpdates()
layout:update()
end
function Market.loadMarketItems(category)
@ -376,26 +655,46 @@ function Market.loadMarketItems(category)
initMarketItems()
end
currentItems = {}
clearItems()
for i = 1, #marketItems do
local item = marketItems[i]
if isValidItem(item, category) then
if isItemValid(item, category) then
table.insert(currentItems, item)
end
end
updateItemsWidget()
Market.refreshItemsWidget()
end
function Market.loadDepotItems(depotItems)
information.depotItems = {}
local items = {}
for i = 1, #depotItems do
local data = depotItems[i]
local newItem = Item.create(data[1])
if not newItem then
break
local id, count = data[1], data[2]
local newItem = nil
if count > 100 then
local createCount = math.floor(count/100)
local remainder = count % 100
for i = 1, createCount do
local newItem = Item.create(id)
if i == createCount and remainder > 0 then
newItem:setCount(remainder)
else
newItem:setCount(100)
end
table.insert(items, newItem)
end
else
local newItem = Item.create(id)
newItem:setCount(count)
table.insert(items, newItem)
end
newItem:setCount(data[2])
end
for _, newItem in pairs(items) do
local marketData = newItem:getMarketData()
if not table.empty(marketData) then
@ -408,141 +707,56 @@ function Market.loadDepotItems(depotItems)
end
end
function Market.updateCurrentItems()
-- get market category
local id = getMarketCategoryId(categoryList:getCurrentOption().text)
if id == MarketCategory.MetaWeapons then
id = getMarketCategoryId(subCategoryList:getCurrentOption().text)
function Market.createNewOffer()
local type = offerTypeList:getCurrentOption().text
if type == 'Sell' then
type = MarketAction.Sell
else
type = MarketAction.Buy
end
Market.loadMarketItems(id)
end
function Market.updateOffers(offers)
marketOffers[MarketAction.Buy] = {}
marketOffers[MarketAction.Sell] = {}
if not buyOfferTable or not sellOfferTable then
if not Market.isItemSelected() then
return
end
buyOfferTable:clearData()
sellOfferTable:clearData()
local spriteId = selectedItem.item.ptr:getId()
local piecePrice = piecePriceEdit:getValue()
local totalPrice = totalPriceEdit:getValue()
local amount = amountEdit:getValue()
local anonymous = anonymous:isChecked() and 1 or 0
for k, offer in pairs(offers) do
if offer and offer:getAction() == MarketAction.Buy then
local data = {
{['text'] = offer:getPlayer(), ['width'] = 100},
{['text'] = offer:getAmount(), ['width'] = 60},
{['text'] = offer:getPrice()*offer:getAmount(), ['width'] = 90},
{['text'] = offer:getPrice(), ['width'] = 80},
{['text'] = offer:getTimeStamp(), ['width'] = 120}
}
buyOfferTable:addRow(data)
table.insert(marketOffers[MarketAction.Buy], offer)
else
local data = {
{['text'] = offer:getPlayer(), ['width'] = 100},
{['text'] = offer:getAmount(), ['width'] = 60},
{['text'] = offer:getPrice()*offer:getAmount(), ['width'] = 90},
{['text'] = offer:getPrice(), ['width'] = 80},
{['text'] = offer:getTimeStamp(), ['width'] = 120}
}
sellOfferTable:addRow(data)
table.insert(marketOffers[MarketAction.Sell], offer)
local errorMsg = ''
if piecePrice > piecePriceEdit.maximum then
errorMsg = errorMsg..'Price is too high.\n'
elseif piecePrice < piecePriceEdit.minimum then
errorMsg = errorMsg..'Price is too low.\n'
end
if amount > amountEdit.maximum then
errorMsg = errorMsg..'Amount is too high.\n'
elseif amount < amountEdit.minimum then
errorMsg = errorMsg..'Amount is too low.\n'
end
end
function Market.updateDetails(itemId, descriptions, purchaseStats, saleStats)
if not selectedItem then
if errorMsg ~= '' then
UIMessageBox.display('Error', errorMsg, MessageBoxOk)
return
end
selectedItem.item.details = {
descriptions = descriptions,
purchaseStats = purchaseStats,
saleStats = saleStats
}
-- update item details
detailsTable:clearData()
for k, desc in pairs(descriptions) do
local columns = {
{['text'] = getMarketDescriptionName(desc[1])..':'},
{['text'] = desc[2], ['width'] = 330}
}
detailsTable:addRow(columns)
end
-- update sale item statistics
sellStatsTable:clearData()
if table.empty(saleStats) then
sellStatsTable:addRow({{['text'] = 'No information'}})
else
for k, stat in pairs(saleStats) do
if not table.empty(stat) then
sellStatsTable:addRow({{['text'] = 'Total Transations:'},
{['text'] = stat[1], ['width'] = 270}})
sellStatsTable:addRow({{['text'] = 'Highest Price:'},
{['text'] = stat[3], ['width'] = 270}})
sellStatsTable:addRow({{['text'] = 'Average Price:'},
{['text'] = math.floor(stat[2]/stat[1])}})
sellStatsTable:addRow({{['text'] = 'Lowest Price:'},
{['text'] = stat[4], ['width'] = 270}})
end
end
end
-- update buy item statistics
buyStatsTable:clearData()
if table.empty(purchaseStats) then
buyStatsTable:addRow({{['text'] = 'No information'}})
else
for k, stat in pairs(purchaseStats) do
if not table.empty(stat) then
buyStatsTable:addRow({{['text'] = 'Total Transations:'},
{['text'] = stat[1], ['width'] = 270}})
buyStatsTable:addRow({{['text'] = 'Highest Price:'},
{['text'] = stat[3], ['width'] = 270}})
buyStatsTable:addRow({{['text'] = 'Average Price:'},
{['text'] = math.floor(stat[2]/stat[1]), ['width'] = 270}})
buyStatsTable:addRow({{['text'] = 'Lowest Price:'},
{['text'] = stat[4], ['width'] = 270}})
end
end
end
MarketProtocol.sendMarketCreateOffer(type, spriteId, amount, piecePrice, anonymous)
Market.refreshItemsWidget(spriteId)
Market.resetCreateOffer()
end
function Market.updateSelectedItem(newItem)
selectedItem.item = newItem
if selectedItem and not table.empty(selectedItem.item) then
if selectedItem.item.ptr then
selectedItem:setItem(selectedItem.item.ptr)
nameLabel:setText(selectedItem.item.marketData.name)
MarketProtocol.sendMarketBrowse(selectedItem.item.ptr:getId()) -- send browsed msg
end
else
selectedItem:setItem(nil)
nameLabel:setText(tr('No item selected.'))
function Market.onItemBoxChecked(widget)
if widget:isChecked() then
updateSelectedItem(widget.item)
end
end
function Market.onMarketEnter(depotItems, offers, balance, vocation)
if marketWindow:isVisible() then
return
end
marketOffers[MarketAction.Buy] = {}
marketOffers[MarketAction.Sell] = {}
--[[
TODO:
* clear filters on enter
* add market reset function
]]
information.balance = balance
updateBalance(balance)
information.totalOffers = offers
if vocation < 0 then
local player = g_game.getLocalPlayer()
@ -552,10 +766,10 @@ function Market.onMarketEnter(depotItems, offers, balance, vocation)
information.vocation = vocation
end
Market.loadDepotItems(depotItems)
if table.empty(currentItems) then
Market.loadMarketItems(MarketCategory.First)
end
Market.loadDepotItems(depotItems)
-- build offer table header
if buyOfferTable and not buyOfferTable:hasHeader() then
@ -565,14 +779,10 @@ function Market.onMarketEnter(depotItems, offers, balance, vocation)
sellOfferTable:addHeaderRow(offerTableHeader)
end
local currentItem = radioItemSet:getSelectedWidget()
if currentItem then
-- Uncheck selected item, cannot make protocol calls to resend marketBrowsing
clearSelectedItem()
end
if g_game.isOnline() then
marketWindow:lock()
marketWindow:show()
end
end
function Market.onMarketLeave()
@ -580,15 +790,9 @@ function Market.onMarketLeave()
end
function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats)
Market.updateDetails(itemId, descriptions, purchaseStats, saleStats)
updateDetails(itemId, descriptions, purchaseStats, saleStats)
end
function Market.onMarketBrowse(offers)
Market.updateOffers(offers)
end
function Market.onItemBoxChecked(widget)
if widget:isChecked() then
Market.updateSelectedItem(widget.item)
end
updateOffers(offers)
end

@ -1,16 +1,9 @@
Module
name: game_market
description: Manage the Players Market system
description: Global item market system
author: BeniS
website: www.otclient.info
@onLoad: |
dofile 'marketoffer'
dofile 'marketprotocol'
dofile 'market'
MarketProtocol.init()
Market.init()
@onUnload: |
MarketProtocol.terminate()
Market.terminate()
sandboxed: true
scripts: [marketoffer.lua, marketprotocol.lua, market.lua]
@onLoad: init()
@onUnload: terminate()

@ -3,8 +3,8 @@ MarketWindow < MainWindow
!text: tr('Market')
size: 700 510
@onEnter: self:hide() self:unlock()
@onEscape: self:hide() self:unlock()
@onEnter: self:hide() self:unlock() Market.clearSelectedItem()
@onEscape: self:hide() self:unlock() Market.clearSelectedItem()
// Main Panel Window
@ -24,3 +24,11 @@ MarketWindow < MainWindow
padding: 3
border-width: 1
border-color: #000000
Label
id: balanceLabel
!text: tr('Balance: 10000')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: parent.top
anchors.right: parent.right

@ -46,15 +46,15 @@ MarketOffer.new = function(offerId, action, item, amount, price, playerName, sta
return offer
end
function MarketOffer:isEqual(offer)
return self.offer[OFFER_TIMESTAMP] == offer[OFFER_TIMESTAMP] and self.offer[OFFER_COUNTER] == offer[OFFER_COUNTER]
function MarketOffer:isEqual(id)
return self.id[OFFER_TIMESTAMP] == id[OFFER_TIMESTAMP] and self.id[OFFER_COUNTER] == id[OFFER_COUNTER]
end
function MarketOffer:isLessThan(offer)
return self.offer[OFFER_TIMESTAMP] <= offer[OFFER_TIMESTAMP] and self.offer[OFFER_COUNTER] < offer[OFFER_COUNTER]
function MarketOffer:isLessThan(id)
return self.id[OFFER_TIMESTAMP] <= id[OFFER_TIMESTAMP] and self.id[OFFER_COUNTER] < id[OFFER_COUNTER]
end
function MarketOffer:isNull(offer)
function MarketOffer:isNull()
return table.empty(self.id)
end

@ -44,8 +44,8 @@ local function parseMarketEnter(msg)
local offers = msg:getU8()
local depotItems = {}
local depotCount = (msg:getU16() - 1)
for i = 0, depotCount do
local depotCount = msg:getU16()
for i = 1, depotCount do
local itemId = msg:getU16() -- item id
local itemCount = msg:getU16() -- item count
@ -103,13 +103,13 @@ local function parseMarketBrowse(msg)
local var = msg:getU16()
local offers = {}
local buyOfferCount = (msg:getU32() - 1)
for i = 0, buyOfferCount do
local buyOfferCount = msg:getU32()
for i = 1, buyOfferCount do
table.insert(offers, readMarketOffer(msg, MarketAction.Buy, var))
end
local sellOfferCount = (msg:getU32() - 1)
for i = 0, sellOfferCount do
local sellOfferCount = msg:getU32()
for i = 1, sellOfferCount do
table.insert(offers, readMarketOffer(msg, MarketAction.Sell, var))
end
@ -118,7 +118,7 @@ local function parseMarketBrowse(msg)
end
-- public functions
function MarketProtocol.init()
function initProtocol()
connect(g_game, { onGameStart = MarketProtocol.registerProtocol,
onGameEnd = MarketProtocol.unregisterProtocol })
@ -128,7 +128,7 @@ function MarketProtocol.init()
end
end
function MarketProtocol.terminate()
function terminateProtocol()
disconnect(g_game, { onGameStart = MarketProtocol.registerProtocol,
onGameEnd = MarketProtocol.unregisterProtocol })

@ -1,8 +1,8 @@
MarketButtonBox < UICheckBox
font: verdana-11px-antialised
font: verdana-11px-rounded
color: #f55e5ebb
size: 106 22
text-offset: 0 0
text-offset: 0 2
text-align: center
image-source: /images/tabbutton_rounded.png
image-clip: 0 0 20 20

@ -1,8 +1,8 @@
MarketComboBoxPopupMenuButton < UIButton
height: 18
font: verdana-11px-antialised
font: verdana-11px-rounded
text-align: left
text-offset: 2 0
text-offset: 2 2
color: #aaaaaa
background-color: alpha
@ -28,10 +28,10 @@ MarketComboBoxPopupMenu < UIPopupMenu
padding: 1
MarketComboBox < UIComboBox
font: verdana-11px-antialised
font: verdana-11px-rounded
color: #aaaaaa
size: 86 20
text-offset: 3 0
text-offset: 3 2
text-align: left
image-source: /images/combobox_rounded.png
image-border: 1

@ -4,6 +4,8 @@ MarketTabBarPanel < Panel
MarketTabBarButton < UIButton
size: 20 25
image-source: /images/tabbutton_square.png
font: verdana-11px-rounded
text-offset: 0 2
image-clip: 0 0 20 20
image-border: 2
icon-color: white

@ -18,7 +18,7 @@ Panel
MarketTabBar
id: rightTabBar
width: 157
width: 166
height:25
anchors.top: parent.top
anchors.right: parent.right
@ -48,7 +48,142 @@ Panel
Label
id: nameLabel
!text: tr('No item selected.')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: prev.top
anchors.left: prev.right
anchors.right: parent.right
margin-left: 5
Label
id: createLabel
!text: tr('Create New Offer')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: rightTabBar.top
anchors.left: rightTabContent.left
margin-top: 355
margin-left: 6
Label
id: offerTypeLabel
!text: tr('Offer Type:')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: prev.bottom
anchors.left: prev.left
margin-top: 7
MarketComboBox
id: offerTypeComboBox
!text: tr('Please Select')
anchors.top: prev.bottom
anchors.left: createLabel.left
margin-top: 3
width: 105
$disabled:
color: #aaaaaa44
Label
id: totalPriceLabel
!text: tr('Total Price:')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: offerTypeLabel.top
anchors.left: prev.right
margin-left: 7
SpinBox
id: totalPriceEdit
anchors.top: prev.bottom
anchors.left: prev.left
margin-top: 3
width: 75
minimum: 1
maximum: 99999999
$disabled:
color: #aaaaaa44
Label
id: piecePriceLabel
!text: tr('Piece Price:')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: offerTypeLabel.top
anchors.left: prev.right
margin-left: 7
SpinBox
id: piecePriceEdit
anchors.top: prev.bottom
anchors.left: prev.left
margin-top: 3
width: 75
minimum: 1
maximum: 99999999
$disabled:
color: #aaaaaa44
Label
id: amountLabel
!text: tr('Amount:')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: offerTypeLabel.top
anchors.left: prev.right
margin-left: 32
PreviousButton
id: prevAmountButton
anchors.verticalCenter: piecePriceEdit.verticalCenter
anchors.left: piecePriceEdit.right
margin-left: 7
@onClick: Market.decrementAmount()
SpinBox
id: amountEdit
anchors.verticalCenter: prev.verticalCenter
anchors.left: prev.right
margin-left: 3
width: 55
minimum: 1
maximum: 999999
NextButton
id: nextAmountButton
anchors.verticalCenter: piecePriceEdit.verticalCenter
anchors.left: prev.right
margin-left: 3
@onClick: Market.incrementAmount()
Button
id: createOfferButton
!text: tr('Create Offer')
anchors.verticalCenter: prev.verticalCenter
anchors.left: prev.right
margin-left: 7
width: 90
//@onClick: g_game.closeNpcTrade()
CheckBox
id: anonymousCheckBox
!text: tr('Anonymous')
anchors.left: prev.left
anchors.bottom: prev.top
margin-bottom: 6
@onSetup: self:setChecked(false)
height: 16
width: 70
Label
id: feeLabel
!text: tr('')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: createOfferButton.bottom
anchors.right: parent.right
margin-right: 8
margin-top: 3

@ -1,14 +1,15 @@
MarketItemBox < UICheckBox
id: itemBox
border-width: 1
border-color: #000000
color: #aaaaaa
text-align: center
text-offset: 0 20
@onCheckChange: Market.onItemBoxChecked(self)
Item
id: item
phantom: true
text-offset: 0 13
text-align: right
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin: 1

@ -25,9 +25,9 @@ Panel
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-top: 55
margin-top: 63
margin-left: 6
margin-bottom: 75
margin-bottom: 85
margin-right: 6
padding: 1
focusable: false

@ -49,6 +49,8 @@ Panel
Label
!text: tr('Sell Offers')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: parent.top
anchors.left: parent.left
margin-top: 44
@ -59,7 +61,7 @@ Panel
anchors.top: prev.bottom
anchors.left: prev.left
anchors.right: parent.right
height: 120
height: 115
margin-top: 5
margin-bottom: 5
margin-right: 6
@ -101,6 +103,8 @@ Panel
Label
!text: tr('Buy Offers')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: prev.top
anchors.left: parent.left
margin-top: 9
@ -114,7 +118,7 @@ Panel
margin-top: 5
margin-bottom: 5
margin-right: 6
height: 120
height: 115
padding: 1
focusable: false
background-color: #222833

@ -20,6 +20,8 @@ Panel
Label
!text: tr('Buy Offers')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@ -62,6 +64,8 @@ Panel
Label
!text: tr('Sell Offers')
font: verdana-11px-rounded
text-offset: 0 2
anchors.top: buyStatsTable.bottom
anchors.left: parent.left
margin-top: 9
@ -73,7 +77,7 @@ Panel
anchors.left: buyStatsTable.left
anchors.right: buyStatsTable.right
margin-top: 6
height: 122
height: 112
padding: 1
focusable: false
background-color: #222833

@ -1,3 +1,21 @@
MarketAction = {
Buy = 0,
Sell = 1
}
MarketRequest = {
MyOffers = 0xFFFE,
MyHistory = 0xFFFF
}
MarketOfferState = {
Active = 0,
Cancelled = 1,
Expired = 2,
Accepted = 3,
AcceptedEx = 255
}
MarketCategory = {
All = 0,
Armors = 1,
@ -64,23 +82,18 @@ MarketCategoryStrings = {
[255] = 'Weapons'
}
MarketAction = {
Buy = 0,
Sell = 1
}
MarketRequest = {
MyOffers = 0xFFFE,
MyHistory = 0xFFFF
}
function getMarketCategoryName(id)
if table.hasKey(MarketCategoryStrings, id) then
return MarketCategoryStrings[id]
end
end
MarketOfferState = {
Active = 0,
Cancelled = 1,
Expired = 2,
Accepted = 3,
AcceptedEx = 255
}
function getMarketCategoryId(name)
local id = table.find(MarketCategoryStrings, name)
if id then
return id
end
end
MarketItemDescription = {
Armor = 1,
@ -121,6 +134,19 @@ MarketItemDescriptionStrings = {
[15] = 'Weight'
}
function getMarketDescriptionName(id)
if table.hasKey(MarketItemDescriptionStrings, id) then
return MarketItemDescriptionStrings[id]
end
end
function getMarketDescriptionId(name)
local id = table.find(MarketItemDescriptionStrings, name)
if id then
return id
end
end
MarketSlotFilters = {
[InventorySlotOther] = "Two-Handed",
[InventorySlotLeft] = "One-Handed",
@ -135,3 +161,16 @@ MarketFilters = {
MarketFilters.First = MarketFilters.vocation
MarketFilters.Last = MarketFilters.depot
function getMarketSlotFilterId(name)
local id = table.find(MarketSlotFilters, name)
if id then
return id
end
end
function getMarketSlotFilterName(id)
if table.hasKey(MarketSlotFilters, id) then
return MarketSlotFilters[id]
end
end
Loading…
Cancel
Save