tibia-client/modules/game_market/market.lua

595 lines
16 KiB
Lua
Raw Normal View History

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 offerTableHeader = {
{['text'] = 'Player Name', ['width'] = 100},
{['text'] = 'Amount', ['width'] = 60},
{['text'] = 'Total Price', ['width'] = 90},
{['text'] = 'Peice 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)
if item.marketData.category ~= category and category ~= MarketCategory[0] then
return false
end
-- filter item
local slotFilter = false
if slotFilterList:isEnabled() then
slotFilter = getMarketSlotFilterId(slotFilterList:getCurrentOption().text)
end
local marketData = item.marketData
local filterVocation = filterButtons[MarketFilters.Vocation]:isChecked()
local filterLevel = filterButtons[MarketFilters.Level]:isChecked()
local filterDepot = filterButtons[MarketFilters.Depot]:isChecked()
if slotFilter then
if slotFilter ~= 255 and item.ptr:getClothSlot() ~= slotFilter then
return false
end
end
local player = g_game.getLocalPlayer()
if filterLevel and marketData.requiredLevel and player:getLevel() < marketData.requiredLevel then
return false
end
if filterVocation and marketData.restrictVocation > 0 then
local voc = Bit.bit(information.vocation)
if not Bit.hasBit(marketData.restrictVocation, voc) then
return false
end
end
if filterDepot and not Market.depotContains(item.ptr:getId()) 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.')
selectedItem:setItem(nil)
selectedItem.item = {}
detailsTable:clearData()
buyStatsTable:clearData()
sellStatsTable:clearData()
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 updateItemsWidget()
itemsPanel = browsePanel:recursiveGetChildById('itemsPanel')
local layout = itemsPanel:getLayout()
layout:disableUpdates()
clearSelectedItem()
itemsPanel:destroyChildren()
if radioItemSet then
radioItemSet:destroy()
end
radioItemSet = UIRadioGroup.create()
for i = 1, #currentItems do
local item = currentItems[i]
local itemBox = g_ui.createWidget('MarketItemBox', itemsPanel)
local itemWidget = itemBox:getChildById('item')
itemBox.item = item
itemWidget:setItem(item.ptr)
radioItemSet:addWidget(itemBox)
end
layout:enableUpdates()
layout:update()
end
local function onUpdateCategory(combobox, option)
local id = getMarketCategoryId(option)
if id == MarketCategory.MetaWeapons then
-- enable and load weapons filter/items
subCategoryList:setEnabled(true)
slotFilterList:setEnabled(true)
local subId = getMarketCategoryId(subCategoryList:getCurrentOption().text)
Market.loadMarketItems(subId)
else
subCategoryList:setEnabled(false)
slotFilterList:setEnabled(false)
Market.loadMarketItems(id) -- load standard filter
end
end
local function onUpdateSubCategory(combobox, option)
local id = getMarketCategoryId(option)
Market.loadMarketItems(id)
-- setup slot filter
slotFilterList:clearOptions()
local subId = getMarketCategoryId(subCategoryList:getCurrentOption().text)
local slots = MarketCategoryWeapons[subId].slots
for _, slot in pairs(slots) do
if table.hasKey(MarketSlotFilters, slot) then
slotFilterList:addOption(MarketSlotFilters[slot])
end
end
slotFilterList:setEnabled(true)
end
local function onUpdateSlotFilter(combobox, option)
Market.updateCurrentItems()
end
local function initInterface()
-- TODO: clean this up
-- 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)
-- setup selected item
nameLabel = marketOffersPanel:recursiveGetChildById('nameLabel')
selectedItem = marketOffersPanel:recursiveGetChildById('selectedItem')
selectedItem.item = {}
-- setup filters
filterButtons[MarketFilters.Vocation] = browsePanel:getChildById('filterVocation')
filterButtons[MarketFilters.Level] = browsePanel:getChildById('filterLevel')
filterButtons[MarketFilters.Depot] = browsePanel:getChildById('filterDepot')
categoryList = browsePanel:getChildById('categoryComboBox')
subCategoryList = browsePanel:getChildById('subCategoryComboBox')
slotFilterList = browsePanel:getChildById('typeComboBox')
slotFilterList:addOption(MarketSlotFilters[255])
slotFilterList:setEnabled(false)
for i = MarketCategory.First, MarketCategory.Last do
if i >= MarketCategory.Ammunition and i <= MarketCategory.WandsRods then
subCategoryList:addOption(getMarketCategoryName(i))
else
categoryList:addOption(getMarketCategoryName(i))
end
end
categoryList:addOption(getMarketCategoryName(255)) -- meta weapons
categoryList:setCurrentOption(getMarketCategoryName(MarketCategory.First))
subCategoryList:setEnabled(false)
-- hook item filters
categoryList.onOptionChange = onUpdateCategory
subCategoryList.onOptionChange = onUpdateSubCategory
slotFilterList.onOptionChange = onUpdateSlotFilter
-- get tables
buyOfferTable = itemOffersPanel:recursiveGetChildById('buyingTable')
sellOfferTable = itemOffersPanel:recursiveGetChildById('sellingTable')
detailsTable = itemDetailsPanel:recursiveGetChildById('detailsTable')
buyStatsTable = itemStatsPanel:recursiveGetChildById('buyStatsTable')
sellStatsTable = itemStatsPanel:recursiveGetChildById('sellStatsTable')
end
function Market.init()
marketWindow = g_ui.createWidget('MarketWindow', rootWidget)
marketWindow:hide()
initInterface() -- build interface
initMarketItems()
end
function Market.terminate()
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 = {}
Market = nil
end
function Market.depotContains(itemId)
for i = 1, #information.depotItems do
local item = information.depotItems[i]
if item.ptr:getId() == itemId then
return true
end
end
return false
end
function Market.loadMarketItems(category)
if table.empty(marketItems) then
initMarketItems()
end
currentItems = {}
for i = 1, #marketItems do
local item = marketItems[i]
if isValidItem(item, category) then
table.insert(currentItems, item)
end
end
updateItemsWidget()
end
function Market.loadDepotItems(depotItems)
information.depotItems = {}
for i = 1, #depotItems do
local data = depotItems[i]
local newItem = Item.create(data[1])
if not newItem then
break
end
newItem:setCount(data[2])
local marketData = newItem:getMarketData()
if not table.empty(marketData) then
local item = {
ptr = newItem,
marketData = marketData
}
table.insert(information.depotItems, item)
end
end
end
function Market.updateCurrentItems()
-- get market category
local id = getMarketCategoryId(categoryList:getCurrentOption().text)
if id == MarketCategory.MetaWeapons then
id = getMarketCategoryId(subCategoryList:getCurrentOption().text)
end
Market.loadMarketItems(id)
end
function Market.updateOffers(offers)
marketOffers[MarketAction.Buy] = {}
marketOffers[MarketAction.Sell] = {}
if not buyOfferTable or not sellOfferTable then
return
end
buyOfferTable:clearData()
sellOfferTable:clearData()
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)
end
end
end
function Market.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
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.'))
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
information.totalOffers = offers
if vocation < 0 then
local player = g_game.getLocalPlayer()
if player then information.vocation = player:getVocation() end
else
-- vocation must be compatible with < 950
information.vocation = vocation
end
if table.empty(currentItems) then
Market.loadMarketItems(MarketCategory.First)
end
Market.loadDepotItems(depotItems)
-- build offer table header
if buyOfferTable and not buyOfferTable:hasHeader() then
buyOfferTable:addHeaderRow(offerTableHeader)
end
if sellOfferTable and not sellOfferTable:hasHeader() then
sellOfferTable:addHeaderRow(offerTableHeader)
end
local currentItem = radioItemSet:getSelectedWidget()
if currentItem then
-- Uncheck selected item, cannot make protocol calls to resend marketBrowsing
clearSelectedItem()
end
marketWindow:lock()
marketWindow:show()
end
function Market.onMarketLeave()
marketWindow:hide()
end
function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats)
Market.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
end