From 6c281a828ca0655f4a6ab109060217bec6eb01a0 Mon Sep 17 00:00:00 2001 From: BeniS Date: Sun, 29 Jul 2012 01:41:10 +1200 Subject: [PATCH] Market fixes for creating offers, got Tibia working properly with market, fixes to statistics. --- modules/corelib/ui/uitable.lua | 4 + modules/game_market/market.lua | 169 ++++++++++++++++++------- modules/game_market/market.otmod | 2 +- modules/game_market/market.otui | 4 +- modules/game_market/marketoffer.lua | 28 ++-- modules/game_market/marketprotocol.lua | 16 ++- modules/game_market/offerstatistic.lua | 101 +++++++++++++++ modules/game_minimap/minimap.otui | 14 +- 8 files changed, 266 insertions(+), 72 deletions(-) create mode 100644 modules/game_market/offerstatistic.lua diff --git a/modules/corelib/ui/uitable.lua b/modules/corelib/ui/uitable.lua index f6ac66ff..aee0f811 100644 --- a/modules/corelib/ui/uitable.lua +++ b/modules/corelib/ui/uitable.lua @@ -31,6 +31,7 @@ function UITable:onDestroy() self.columns = {} self.headerRow = {} self.selectedRow = nil + self.dataSpace:destroyChildren() self.dataSpace = nil end @@ -69,6 +70,9 @@ function UITable:clearData() return end self.dataSpace:destroyChildren() + self.selectedRow = nil + self.columns = {} + self.rows = {} end function UITable:addHeaderRow(data) diff --git a/modules/game_market/market.lua b/modules/game_market/market.lua index 297657fe..23def568 100644 --- a/modules/game_market/market.lua +++ b/modules/game_market/market.lua @@ -122,8 +122,12 @@ local function refreshFee() end local function updateOffers(offers) + selectedOffer[MarketAction.Buy] = {} + selectedOffer[MarketAction.Sell] = {} + marketOffers[MarketAction.Buy] = {} marketOffers[MarketAction.Sell] = {} + if not buyOfferTable or not sellOfferTable then return end @@ -132,7 +136,7 @@ local function updateOffers(offers) balanceLabel:setColor('#bbbbbb') for k, offer in pairs(offers) do - if offer and offer:getAction() == MarketAction.Buy then + if offer and offer:getType() == MarketAction.Buy then local data = { {['text'] = offer:getPlayer(), ['width'] = 100}, {['text'] = offer:getAmount(), ['width'] = 60}, @@ -160,11 +164,6 @@ 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() @@ -181,21 +180,38 @@ local function updateDetails(itemId, descriptions, purchaseStats, saleStats) 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}}) + local transactions, totalPrice, highestPrice, lowestPrice = 0, 0, 0, 0 + for _, stat in pairs(saleStats) do + if not stat:isNull() then + transactions = transactions + stat:getTransactions() + totalPrice = totalPrice + stat:getTotalPrice() + local newHigh = stat:getHighestPrice() + if newHigh > highestPrice then + highestPrice = newHigh + end + local newLow = stat:getLowestPrice() + -- ?? getting '4294967295' result from lowest price in 9.60 cipsoft + if (lowestPrice == 0 or newLow < lowestPrice) and newLow ~= 4294967295 then + lowestPrice = newLow + end + end + end + sellStatsTable:addRow({{['text'] = 'Total Transations:'}, + {['text'] = transactions, ['width'] = 270}}) - sellStatsTable:addRow({{['text'] = 'Average Price:'}, - {['text'] = math.floor(stat[2]/stat[1])}}) + sellStatsTable:addRow({{['text'] = 'Highest Price:'}, + {['text'] = highestPrice, ['width'] = 270}}) - sellStatsTable:addRow({{['text'] = 'Lowest Price:'}, - {['text'] = stat[4], ['width'] = 270}}) - end + if totalPrice > 0 and transactions > 0 then + sellStatsTable:addRow({{['text'] = 'Average Price:'}, + {['text'] = math.floor(totalPrice/transactions), ['width'] = 270}}) + else + sellStatsTable:addRow({{['text'] = 'Average Price:'}, + {['text'] = 0, ['width'] = 270}}) end + + sellStatsTable:addRow({{['text'] = 'Lowest Price:'}, + {['text'] = lowestPrice, ['width'] = 270}}) end -- update buy item statistics @@ -203,21 +219,38 @@ local function updateDetails(itemId, descriptions, purchaseStats, saleStats) 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}}) + local transactions, totalPrice, highestPrice, lowestPrice = 0, 0, 0, 0 + for _, stat in pairs(purchaseStats) do + if not stat:isNull() then + transactions = transactions + stat:getTransactions() + totalPrice = totalPrice + stat:getTotalPrice() + local newHigh = stat:getHighestPrice() + if newHigh > highestPrice then + highestPrice = newHigh + end + local newLow = stat:getLowestPrice() + -- ?? getting '4294967295' result from lowest price in 9.60 cipsoft + if (lowestPrice == 0 or newLow < lowestPrice) and newLow ~= 4294967295 then + lowestPrice = newLow + end + end + end + buyStatsTable:addRow({{['text'] = 'Total Transations:'}, + {['text'] = transactions, ['width'] = 270}}) - buyStatsTable:addRow({{['text'] = 'Average Price:'}, - {['text'] = math.floor(stat[2]/stat[1]), ['width'] = 270}}) + buyStatsTable:addRow({{['text'] = 'Highest Price:'}, + {['text'] = highestPrice, ['width'] = 270}}) - buyStatsTable:addRow({{['text'] = 'Lowest Price:'}, - {['text'] = stat[4], ['width'] = 270}}) - end + if totalPrice > 0 and transactions > 0 then + buyStatsTable:addRow({{['text'] = 'Average Price:'}, + {['text'] = math.floor(totalPrice/transactions), ['width'] = 270}}) + else + buyStatsTable:addRow({{['text'] = 'Average Price:'}, + {['text'] = 0, ['width'] = 270}}) end + + buyStatsTable:addRow({{['text'] = 'Lowest Price:'}, + {['text'] = lowestPrice, ['width'] = 270}}) end end @@ -228,9 +261,8 @@ local function updateSelectedItem(newItem) if Market.isItemSelected() then selectedItem:setItem(selectedItem.item.ptr) nameLabel:setText(selectedItem.item.marketData.name) - -- update offer types - Market.enableCreateOffer(true) + Market.enableCreateOffer(true)-- update offer types MarketProtocol.sendMarketBrowse(selectedItem.item.ptr:getId()) -- send browsed msg else Market.Market.clearSelectedItem() @@ -251,6 +283,42 @@ local function updateBalance(balance) balanceLabel:resizeToText() end +local function updateDepotItemCount(itemId, amount) + if Market.depotContains(itemId) < amount then + return false + end + for i = 1, #information.depotItems do + local depotItem = information.depotItems[i] + if depotItem and itemId == depotItem.ptr:getId() then + local depotItemCount = depotItem.ptr:getCount() + + if depotItemCount <= 100 and depotItemCount >= amount then + if (depotItemCount - amount) <= 0 then + table.remove(information.depotItems, i) + else + depotItem.ptr:setCount(depotItemCount - amount) + information.depotItems[i] = depotItem + end + return true + else + local removeCount = math.floor(amount/100) + local remainder = amount % depotItemCount + if remainder > 0 then + removeCount = removeCount + 1 + end + for i = 1, removeCount do + if i == removeCount and remainder > 0 then + updateDepotItemCount(itemId, remainder) + else + updateDepotItemCount(itemId, 100) + end + end + return true + end + end + end +end + local function updateFee(price, amount) fee = math.ceil(price / 100 * amount) if fee < 20 then @@ -272,13 +340,13 @@ local function onSelectSellOffer(table, selectedRow, previousSelectedRow) local offer = selectedOffer[MarketAction.Sell] if offer then - if offer:getPrice() > information.balance then + if offer:getTotalPrice() > information.balance then balanceLabel:setColor('#b22222') else local slice = (information.balance / 2) - if (offer:getPrice()/slice) * 100 <= 40 then + if (offer:getTotalPrice()/slice) * 100 <= 40 then color = '#008b00' -- green - elseif (offer:getPrice()/slice) * 100 <= 70 then + elseif (offer:getTotalPrice()/slice) * 100 <= 70 then color = '#eec900' -- yellow else color = '#ee9a00' -- orange @@ -313,10 +381,9 @@ local function onChangeCategory(combobox, option) end local function onChangeSubCategory(combobox, option) - local id = getMarketCategoryId(option) - Market.loadMarketItems(id) - -- setup slot filter + Market.loadMarketItems(getMarketCategoryId(option)) slotFilterList:clearOptions() + local subId = getMarketCategoryId(subCategoryList:getCurrentOption().text) local slots = MarketCategoryWeapons[subId].slots for _, slot in pairs(slots) do @@ -504,8 +571,8 @@ function init() 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() @@ -544,7 +611,7 @@ function Market.clearSelectedItem() nameLabel:setText('No item selected.') selectedItem:setItem(nil) - selectedItem.item = {} + selectedItem = {} detailsTable:clearData() buyStatsTable:clearData() @@ -562,7 +629,7 @@ function Market.depotContains(itemId) local count = 0 for i = 1, #information.depotItems do local item = information.depotItems[i] - if item.ptr:getId() == itemId then + if item and item.ptr:getId() == itemId then count = count + item.ptr:getCount() end end @@ -633,6 +700,7 @@ function Market.refreshItemsWidget(selectItem) end local itemWidget = itemBox:getChildById('item') + item.ptr:setCount(1) -- reset item count for image itemWidget:setItem(item.ptr) local amount = Market.depotContains(item.ptr:getId()) if amount > 0 then @@ -674,10 +742,12 @@ function Market.loadDepotItems(depotItems) local data = depotItems[i] local id, count = data[1], data[2] - local newItem = nil if count > 100 then local createCount = math.floor(count/100) local remainder = count % 100 + if remainder > 0 then + createCount = createCount + 1 + end for i = 1, createCount do local newItem = Item.create(id) if i == createCount and remainder > 0 then @@ -718,7 +788,9 @@ function Market.createNewOffer() if not Market.isItemSelected() then return end - local spriteId = selectedItem.item.ptr:getId() + local item = selectedItem.item + local spriteId = item.ptr:getId() + local piecePrice = piecePriceEdit:getValue() local totalPrice = totalPriceEdit:getValue() local amount = amountEdit:getValue() @@ -742,7 +814,10 @@ function Market.createNewOffer() end MarketProtocol.sendMarketCreateOffer(type, spriteId, amount, piecePrice, anonymous) - Market.refreshItemsWidget(spriteId) + if type == MarketAction.Sell then + updateDepotItemCount(spriteId, amount) -- remove count from depot tmp + Market.refreshItemsWidget(spriteId) + end Market.resetCreateOffer() end @@ -769,6 +844,12 @@ function Market.onMarketEnter(depotItems, offers, balance, vocation) Market.loadDepotItems(depotItems) if table.empty(currentItems) then Market.loadMarketItems(MarketCategory.First) + --[[else + -- TODO: Create function to handle this on showing market (seperate from parsing!) + if Market.isItemSelected() then + local spriteId = selectedItem.item.ptr:getId() + Market.refreshItemsWidget(spriteId) + end]] end -- build offer table header diff --git a/modules/game_market/market.otmod b/modules/game_market/market.otmod index a2fc890c..110e17da 100644 --- a/modules/game_market/market.otmod +++ b/modules/game_market/market.otmod @@ -4,6 +4,6 @@ Module author: BeniS website: www.otclient.info sandboxed: true - scripts: [marketoffer.lua, marketprotocol.lua, market.lua] + scripts: [offerstatistic.lua, marketoffer.lua, marketprotocol.lua, market.lua] @onLoad: init() @onUnload: terminate() diff --git a/modules/game_market/market.otui b/modules/game_market/market.otui index df66011e..349bdd12 100644 --- a/modules/game_market/market.otui +++ b/modules/game_market/market.otui @@ -3,8 +3,8 @@ MarketWindow < MainWindow !text: tr('Market') size: 700 510 - @onEnter: self:hide() self:unlock() Market.clearSelectedItem() - @onEscape: self:hide() self:unlock() Market.clearSelectedItem() + @onEnter: self:hide() self:unlock() Market.clearSelectedItem() MarketProtocol.sendMarketLeave() + @onEscape: self:hide() self:unlock() Market.clearSelectedItem() MarketProtocol.sendMarketLeave() // Main Panel Window diff --git a/modules/game_market/marketoffer.lua b/modules/game_market/marketoffer.lua index df6590c2..ef25fe27 100644 --- a/modules/game_market/marketoffer.lua +++ b/modules/game_market/marketoffer.lua @@ -4,10 +4,10 @@ MarketOffer.__index = MarketOffer local OFFER_TIMESTAMP = 1 local OFFER_COUNTER = 2 -MarketOffer.new = function(offerId, action, item, amount, price, playerName, state) +MarketOffer.new = function(offerId, t, item, amount, price, playerName, state) local offer = { id = {}, - action = nil, + type = nil, item = 0, amount = 0, price = 0, @@ -20,11 +20,11 @@ MarketOffer.new = function(offerId, action, item, amount, price, playerName, sta end offer.id = offerId - action = tonumber(action) - if action ~= MarketAction.Buy and action ~= MarketAction.Sell then - g_logger.error('MarketOffer.new - invalid action provided.') + t = tonumber(t) + if t ~= MarketAction.Buy and t ~= MarketAction.Sell then + g_logger.error('MarketOffer.new - invalid type provided.') end - offer.action = action + offer.type = t if not item then g_logger.error('MarketOffer.new - invalid item provided.') @@ -71,15 +71,15 @@ 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.') +function MarketOffer:setType(t) + if not t or type(t) ~= 'number' then + g_logger.error('MarketOffer.setItem - invalid type provided.') end - self.action = action + self.type = type end -function MarketOffer:getAction() - return self.action +function MarketOffer:getType() + return self.type end function MarketOffer:setItem(item) @@ -115,6 +115,10 @@ function MarketOffer:getPrice() return self.price end +function MarketOffer:getTotalPrice() + return self.price * self.amount +end + function MarketOffer:setPlayer(player) if not player or type(player) ~= 'number' then g_logger.error('MarketOffer.setPlayer - invalid player provided.') diff --git a/modules/game_market/marketprotocol.lua b/modules/game_market/marketprotocol.lua index 5e43a7d9..c316894e 100644 --- a/modules/game_market/marketprotocol.lua +++ b/modules/game_market/marketprotocol.lua @@ -3,6 +3,7 @@ MarketProtocol = {} -- private functions local protocol +local statistics = runinsandbox('offerstatistic.lua') local function send(msg) if protocol then @@ -72,27 +73,30 @@ local function parseMarketDetail(msg) msg:getU16() end end + local time = (os.time() / 1000) * statistics.SECONDS_PER_DAY; local purchaseStats = {} local count = msg:getU8() - for i=1,count do + for i=1, count do local transactions = msg:getU32() -- transaction count local totalPrice = msg:getU32() -- total price local highestPrice = msg:getU32() -- highest price - local lowestPrice = msg: getU32() -- lowest price + local lowestPrice = msg:getU32() -- lowest price - table.insert(purchaseStats, {transactions, totalPrice, highestPrice, lowestPrice}) + local tmp = time - statistics.SECONDS_PER_DAY + table.insert(purchaseStats, OfferStatistic.new(tmp, MarketAction.Buy, transactions, totalPrice, highestPrice, lowestPrice)) end local saleStats = {} count = msg:getU8() - for i=1,count do + for i=1, count do local transactions = msg:getU32() -- transaction count local totalPrice = msg:getU32() -- total price local highestPrice = msg:getU32() -- highest price - local lowestPrice = msg: getU32() -- lowest price + local lowestPrice = msg:getU32() -- lowest price - table.insert(saleStats, {transactions, totalPrice, highestPrice, lowestPrice}) + local tmp = time - statistics.SECONDS_PER_DAY + table.insert(saleStats, OfferStatistic.new(tmp, MarketAction.Sell, transactions, totalPrice, highestPrice, lowestPrice)) end signalcall(Market.onMarketDetail, itemId, descriptions, purchaseStats, saleStats) diff --git a/modules/game_market/offerstatistic.lua b/modules/game_market/offerstatistic.lua new file mode 100644 index 00000000..859679bb --- /dev/null +++ b/modules/game_market/offerstatistic.lua @@ -0,0 +1,101 @@ +OfferStatistic = {} +OfferStatistic.__index = OfferStatistic + +SECONDS_PER_DAY = 86400 + +OfferStatistic.new = function(timestamp, t, transactions, totalPrice, highestPrice, lowestPrice) + local stat = { + time = 0, + type = nil, + transactions = 0, + totalPrice = 0, + highestPrice = 0, + lowestPrice = 0 + } + stat.time = math.floor(timestamp / SECONDS_PER_DAY) * SECONDS_PER_DAY + + if t ~= MarketAction.Buy and t ~= MarketAction.Sell then + g_logger.error('OfferStatistic.new - invalid type provided.') + end + stat.type = t + + stat.transactions = transactions + stat.totalPrice = totalPrice + stat.highestPrice = highestPrice + stat.lowestPrice = lowestPrice + + setmetatable(stat, OfferStatistic) + return stat +end + +function OfferStatistic:isNull() + return self.time == 0 or not self.type +end + +-- Sets/Gets + +function OfferStatistic:setTime(time) + if not time or type(time) ~= 'number' then + g_logger.error('OfferStatistic.setTime - invalid time provided.') + end + self.time = time +end + +function OfferStatistic:getTime() + return self.time +end + +function OfferStatistic:setType(t) + if not t or type(t) ~= 'number' then + g_logger.error('OfferStatistic.setType - invalid type provided.') + end + self.type = t +end + +function OfferStatistic:getType() + return self.type +end + +function OfferStatistic:setTransactions(transactions) + if not transactions or type(transactions) ~= 'number' then + g_logger.error('OfferStatistic.setTransactions - invalid transactions provided.') + end + self.transactions = transactions +end + +function OfferStatistic:getTransactions() + return self.transactions +end + +function OfferStatistic:setTotalPrice(amount) + if not totalPrice or type(totalPrice) ~= 'number' then + g_logger.error('OfferStatistic.setTotalPrice - invalid total price provided.') + end + self.totalPrice = totalPrice +end + +function OfferStatistic:getTotalPrice() + return self.totalPrice +end + +function OfferStatistic:setHighestPrice(highestPrice) + if not highestPrice or type(highestPrice) ~= 'number' then + g_logger.error('OfferStatistic.setHighestPrice - invalid highestPrice provided.') + end + self.highestPrice = highestPrice +end + +function OfferStatistic:getHighestPrice() + return self.highestPrice +end + +function OfferStatistic:setLowestPrice(lowestPrice) + if not lowestPrice or type(lowestPrice) ~= 'number' then + g_logger.error('OfferStatistic.setLowestPrice - invalid lowestPrice provided.') + end + self.lowestPrice = lowestPrice +end + +function OfferStatistic:getLowestPrice() + return self.lowestPrice +end diff --git a/modules/game_minimap/minimap.otui b/modules/game_minimap/minimap.otui index 2cc6e07f..4fa5f051 100644 --- a/modules/game_minimap/minimap.otui +++ b/modules/game_minimap/minimap.otui @@ -62,9 +62,10 @@ MiniWindow enabled: true @onClick: onButtonClick(self:getId()) - ZoomInControl - id: zoomIn - text: + + ZoomOutControl + id: zoomOut + text: - + font: terminus-14px-bold anchors.right: parent.right anchors.bottom: parent.bottom margin-right: 4 @@ -72,10 +73,9 @@ MiniWindow enabled: true @onClick: onButtonClick(self:getId()) - ZoomOutControl - id: zoomOut - text: - - font: terminus-14px-bold + ZoomInControl + id: zoomIn + text: + anchors.right: parent.right anchors.bottom: parent.bottom margin-right: 4