--[[ Finalizing Market: Note: Feel free to work on any area and submit it as a pull request from your git fork. BeniS's Skype: benjiz69 List: * Add offer management: - Current Offers - Offer History * Clean up the interface building - Add a new market interface file to handle building? * Add offer table column ordering. - Player Name, Amount, Total Price, Peice Price and Ends At * Extend information features - Hover over offers for purchase information (balance after transaction, etc) - Display out of trend market offers based on their previous statistics (like cipsoft does) ]] Market = {} local protocol = runinsandbox('marketprotocol') marketWindow = nil mainTabBar = nil displaysTabBar = nil offersTabBar = nil selectionTabBar = nil marketOffersPanel = nil browsePanel = nil overviewPanel = nil itemOffersPanel = nil itemDetailsPanel = nil itemStatsPanel = nil myOffersPanel = nil currentOffersPanel = nil offerHistoryPanel = nil itemsPanel = nil selectedOffer = {} nameLabel = nil feeLabel = nil balanceLabel = nil totalPriceEdit = nil piecePriceEdit = nil amountEdit = nil searchEdit = nil radioItemSet = nil selectedItem = nil offerTypeList = nil categoryList = nil subCategoryList = nil slotFilterList = nil createOfferButton = nil buyButton = nil sellButton = nil anonymous = nil filterButtons = {} buyOfferTable = nil sellOfferTable = nil detailsTable = nil buyStatsTable = nil sellStatsTable = nil offerExhaust = {} marketOffers = {} marketItems = {} information = {} currentItems = {} lastCreatedOffer = 0 fee = 0 loaded = false local offerTableHeader = { {['text'] = 'Player Name', ['width'] = 100}, {['text'] = 'Amount', ['width'] = 60}, {['text'] = 'Total Price', ['width'] = 90}, {['text'] = 'Piece Price', ['width'] = 80}, {['text'] = 'Ends at', ['width'] = 120} } local function isItemValid(item, category, searchFilter) if not item or not item.marketData then return false end if not category then category = MarketCategory.All end if item.marketData.category ~= category and category ~= MarketCategory.All 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 Market.depotContains(item.ptr:getId()) <= 0 then return false end if searchFilter then return marketData.name:lower():find(searchFilter) end return true end local function clearItems() currentItems = {} Market.refreshItemsWidget() end local function clearOffers() marketOffers[MarketAction.Buy] = {} marketOffers[MarketAction.Sell] = {} buyOfferTable:clearData() sellOfferTable:clearData() end local function clearFilters() for _, filter in pairs(filterButtons) do if filter and filter:isChecked() then filter:setChecked(false) end end end local function clearFee() feeLabel:setText('') fee = 0 end 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 addOffer(offer, type) if not offer then return false end local id = offer:getId() local player = offer:getPlayer() local amount = offer:getAmount() local price = offer:getPrice() local timestamp = offer:getTimeStamp() if amount < 1 then return false end if type == MarketAction.Buy then local data = { {['text'] = player, ['width'] = 100}, {['text'] = amount, ['width'] = 60}, {['text'] = price*amount, ['width'] = 90}, {['text'] = price, ['width'] = 80}, {['text'] = string.gsub(os.date('%c', timestamp), " ", " "), ['width'] = 120} } buyOfferTable:addRow(data, id) else local data = { {['text'] = player, ['width'] = 100}, {['text'] = amount, ['width'] = 60}, {['text'] = price*amount, ['width'] = 90}, {['text'] = price, ['width'] = 80}, {['text'] = string.gsub(os.date('%c', timestamp), " ", " "), ['width'] = 120} } sellOfferTable:addRow(data, id) end return true end local function mergeOffer(offer) if not offer then return false end local id = offer:getId() local type = offer:getType() local amount = offer:getAmount() local replaced = false if type == MarketAction.Buy then for i = 1, #marketOffers[MarketAction.Buy] do local o = marketOffers[MarketAction.Buy][i] -- replace existing offer if o:isEqual(id) then marketOffers[MarketAction.Buy][i] = offer replaced = true end end if not replaced then table.insert(marketOffers[MarketAction.Buy], offer) end else for i = 1, #marketOffers[MarketAction.Sell] do local o = marketOffers[MarketAction.Sell][i] -- replace existing offer if o:isEqual(id) then marketOffers[MarketAction.Sell][i] = offer replaced = true end end if not replaced then table.insert(marketOffers[MarketAction.Sell], offer) end end return true end local function updateOffers(offers) if not buyOfferTable or not sellOfferTable then return end balanceLabel:setColor('#bbbbbb') selectedOffer[MarketAction.Buy] = nil selectedOffer[MarketAction.Sell] = nil -- clear existing offer data buyOfferTable:clearData() sellOfferTable:clearData() sellButton:setEnabled(false) buyButton:setEnabled(false) for _, offer in pairs(offers) do mergeOffer(offer) end for type, offers in pairs(marketOffers) do for i = 1, #offers do addOffer(offers[i], type) end end end local function updateDetails(itemId, descriptions, purchaseStats, saleStats) if not selectedItem then return end -- 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 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 '0xffffffff' result from lowest price in 9.60 cipsoft if (lowestPrice == 0 or newLow < lowestPrice) and newLow ~= 0xffffffff then lowestPrice = newLow end end end sellStatsTable:addRow({{['text'] = 'Total Transations:'}, {['text'] = transactions, ['width'] = 270}}) sellStatsTable:addRow({{['text'] = 'Highest Price:'}, {['text'] = highestPrice, ['width'] = 270}}) 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 buyStatsTable:clearData() if table.empty(purchaseStats) then buyStatsTable:addRow({{['text'] = 'No information'}}) else 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 '0xffffffff' result from lowest price in 9.60 cipsoft if (lowestPrice == 0 or newLow < lowestPrice) and newLow ~= 0xffffffff then lowestPrice = newLow end end end buyStatsTable:addRow({{['text'] = 'Total Transations:'}, {['text'] = transactions, ['width'] = 270}}) buyStatsTable:addRow({{['text'] = 'Highest Price:'}, {['text'] = highestPrice, ['width'] = 270}}) 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 local function updateSelectedItem(widget) selectedItem.item = widget.item selectedItem.ref = widget Market.resetCreateOffer() if Market.isItemSelected() then selectedItem:setItem(selectedItem.item.ptr) nameLabel:setText(selectedItem.item.marketData.name) clearOffers() Market.enableCreateOffer(true) -- update offer types MarketProtocol.sendMarketBrowse(selectedItem.item.ptr:getId()) -- send browsed msg else Market.clearSelectedItem() end end local function updateBalance(balance) local balance = tonumber(balance) if not balance then return end if balance < 0 then balance = 0 end information.balance = balance balanceLabel:setText('Balance: '..balance..' gold') 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 local function openAmountWindow(callback, type, actionText) local actionText = actionText or '' if not Market.isOfferSelected(type) then return end amountWindow = g_ui.createWidget('AmountWindow', rootWidget) amountWindow:lock() local item = selectedOffer[type]:getItem() local max = selectedOffer[type]:getAmount(item:getId()) if type == MarketAction.Sell then local depot = Market.depotContains(item:getId()) if max > depot then max = depot end end local itembox = amountWindow:getChildById('item') itembox:setItemId(item:getId()) itembox:setText(1) local scrollbar = amountWindow:getChildById('amountScrollBar') scrollbar:setText(tostring(selectedOffer[type]:getPrice())..'gp') scrollbar:setMaximum(max) scrollbar:setMinimum(1) scrollbar:setValue(1) scrollbar.onValueChange = function(widget, value) widget:setText(tostring(value*selectedOffer[type]:getPrice())..'gp') itembox:setText(tostring(value)) end local okButton = amountWindow:getChildById('buttonOk') if actionText ~= '' then okButton:setText(actionText) end local okFunc = function() local counter = selectedOffer[type]:getCounter() local timestamp = selectedOffer[type]:getTimeStamp() callback(scrollbar:getValue(), timestamp, counter) okButton:getParent():destroy() amountWindow = nil end local cancelButton = amountWindow:getChildById('buttonCancel') local cancelFunc = function() cancelButton:getParent():destroy() amountWindow = nil end amountWindow.onEnter = okFunc amountWindow.onEscape = cancelFunc okButton.onClick = okFunc cancelButton.onClick = cancelFunc end local function onSelectSellOffer(table, selectedRow, previousSelectedRow) updateBalance() for _, offer in pairs(marketOffers[MarketAction.Sell]) do if offer:isEqual(selectedRow.ref) then selectedOffer[MarketAction.Buy] = offer end end local offer = selectedOffer[MarketAction.Buy] if offer then local price = offer:getPrice() if price > information.balance then balanceLabel:setColor('#b22222') -- red buyButton:setEnabled(false) else local slice = (information.balance / 2) if (price/slice) * 100 <= 40 then color = '#008b00' -- green elseif (price/slice) * 100 <= 70 then color = '#eec900' -- yellow else color = '#ee9a00' -- orange end balanceLabel:setColor(color) buyButton:setEnabled(true) end end end local function onSelectBuyOffer(table, selectedRow, previousSelectedRow) updateBalance() for _, offer in pairs(marketOffers[MarketAction.Buy]) do if offer:isEqual(selectedRow.ref) then selectedOffer[MarketAction.Sell] = offer if Market.depotContains(offer:getItem():getId()) > 0 then sellButton:setEnabled(true) else sellButton:setEnabled(false) end end end end local function onChangeCategory(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 onChangeSubCategory(combobox, option) Market.loadMarketItems(getMarketCategoryId(option)) 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 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(category) for c = MarketCategory.First, MarketCategory.Last do marketItems[c] = {} end -- populate all market items local types = g_things.findThingTypeByAttr(ThingAttrMarket, 0) 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 if marketData.category == category or category == MarketCategory.All then -- create new item block local item = { ptr = newItem, marketData = marketData } -- add new market item table.insert(marketItems[marketData.category], item) end end end end 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') mainTabBar:addTab(tr('Market Offers'), marketOffersPanel) selectionTabBar = marketOffersPanel:getChildById('leftTabBar') selectionTabBar:setContentWidget(marketOffersPanel:getChildById('leftTabContent')) browsePanel = g_ui.loadUI('ui/marketoffers/browse') selectionTabBar:addTab(tr('Browse'), browsePanel) overviewPanel = g_ui.loadUI('ui/marketoffers/overview') selectionTabBar:addTab(tr('Overview'), overviewPanel) displaysTabBar = marketOffersPanel:getChildById('rightTabBar') displaysTabBar:setContentWidget(marketOffersPanel:getChildById('rightTabContent')) itemOffersPanel = g_ui.loadUI('ui/marketoffers/itemoffers') displaysTabBar:addTab(tr('Offers'), itemOffersPanel) itemDetailsPanel = g_ui.loadUI('ui/marketoffers/itemdetails') displaysTabBar:addTab(tr('Details'), itemDetailsPanel) itemStatsPanel = g_ui.loadUI('ui/marketoffers/itemstats') displaysTabBar:addTab(tr('Statistics'), itemStatsPanel) -- setup 'My Offer' section tabs myOffersPanel = g_ui.loadUI('ui/myoffers') mainTabBar:addTab(tr('My Offers'), myOffersPanel) offersTabBar = myOffersPanel:getChildById('offersTabBar') offersTabBar:setContentWidget(myOffersPanel:getChildById('offersTabContent')) currentOffersPanel = g_ui.loadUI('ui/myoffers/currentoffers') offersTabBar:addTab(tr('Current Offers'), currentOffersPanel) offerHistoryPanel = g_ui.loadUI('ui/myoffers/offerhistory') offersTabBar:addTab(tr('Offer History'), offerHistoryPanel) balanceLabel = marketWindow:getChildById('balanceLabel') -- setup offers buyButton = itemOffersPanel:getChildById('buyButton') buyButton.onClick = function() openAmountWindow(Market.acceptMarketOffer, MarketAction.Buy, 'Buy') end sellButton = itemOffersPanel:getChildById('sellButton') sellButton.onClick = function() openAmountWindow(Market.acceptMarketOffer, MarketAction.Sell, 'Sell') end -- setup selected item 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') filterButtons[MarketFilters.Depot] = browsePanel:getChildById('filterDepot') filterButtons[MarketFilters.SearchAll] = browsePanel:getChildById('filterSearchAll') searchEdit = browsePanel:getChildById('searchEdit') categoryList = browsePanel:getChildById('categoryComboBox') subCategoryList = browsePanel:getChildById('subCategoryComboBox') slotFilterList = browsePanel:getChildById('slotComboBox') 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 = onChangeCategory subCategoryList.onOptionChange = onChangeSubCategory slotFilterList.onOptionChange = onChangeSlotFilter -- setup tables buyOfferTable = itemOffersPanel:recursiveGetChildById('buyingTable') sellOfferTable = itemOffersPanel:recursiveGetChildById('sellingTable') detailsTable = itemDetailsPanel:recursiveGetChildById('detailsTable') buyStatsTable = itemStatsPanel:recursiveGetChildById('buyStatsTable') sellStatsTable = itemStatsPanel:recursiveGetChildById('sellStatsTable') buyOfferTable.onSelectionChange = onSelectBuyOffer sellOfferTable.onSelectionChange = onSelectSellOffer end function init() g_ui.importStyle('market') g_ui.importStyle('ui/general/markettabs') g_ui.importStyle('ui/general/marketbuttons') g_ui.importStyle('ui/general/marketcombobox') g_ui.importStyle('ui/general/amountwindow') offerExhaust[MarketAction.Sell] = 10 offerExhaust[MarketAction.Buy] = 20 protocol.initProtocol() connect(g_game, { onGameEnd = Market.reset }) connect(g_game, { onGameEnd = Market.close }) marketWindow = g_ui.createWidget('MarketWindow', rootWidget) marketWindow:hide() initInterface() -- build interface end function terminate() protocol.terminateProtocol() disconnect(g_game, { onGameEnd = Market.reset }) disconnect(g_game, { onGameEnd = Market.close }) marketWindow:destroy() Market = nil end function Market.reset() balanceLabel:setColor('#bbbbbb') categoryList:setCurrentOption(getMarketCategoryName(MarketCategory.First)) searchEdit:setText('') clearFilters() if not table.empty(information) then Market.updateCurrentItems() end end function Market.clearSelectedItem() if Market.isItemSelected() then Market.resetCreateOffer() offerTypeList:clearOptions() offerTypeList:setText('Please Select') offerTypeList:setEnabled(false) clearOffers() radioItemSet:selectWidget(nil) nameLabel:setText('No item selected.') selectedItem:setItem(nil) selectedItem.item = nil selectedItem.ref:setChecked(false) selectedItem.ref = nil 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.isOfferSelected(type) return selectedOffer[type] and not selectedOffer[type]:isNull() end function Market.depotContains(itemId) local count = 0 for i = 1, #information.depotItems do local item = information.depotItems[i] if item and item.ptr:getId() == itemId then count = count + item.ptr:getCount() end end 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.close(notify) if notify == nil then notify = true end if not marketWindow:isHidden() then marketWindow:hide() marketWindow:unlock() if notify then MarketProtocol.sendMarketLeave() end end end function Market.incrementAmount() amountEdit:setValue(amountEdit:getValue() + 1) end function Market.decrementAmount() amountEdit:setValue(amountEdit:getValue() - 1) 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() clearFee() 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') item.ptr:setCount(1) -- reset item count for image 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.refreshOffers() if Market.isItemSelected() then Market.onItemBoxChecked(selectedItem.ref) end end function Market.loadMarketItems(category) clearItems() -- check search filter local searchFilter = searchEdit:getText() if searchFilter and searchFilter:len() > 2 then if filterButtons[MarketFilters.SearchAll]:isChecked() then category = MarketCategory.All end end if category == MarketCategory.All then -- loop all categories for category = MarketCategory.First, MarketCategory.Last do for i = 1, #marketItems[category] do local item = marketItems[category][i] if isItemValid(item, category, searchFilter) then table.insert(currentItems, item) end end end else -- loop specific category for i = 1, #marketItems[category] do local item = marketItems[category][i] if isItemValid(item, category, searchFilter) then table.insert(currentItems, item) end end end Market.refreshItemsWidget() end function Market.loadDepotItems(depotItems) information.depotItems = {} local items = {} for i = 1, #depotItems do local data = depotItems[i] local id, count = data[1], data[2] local tmpItem = Item.create(id) if tmpItem:isStackable() then 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 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 else for i = 1, count do table.insert(items, Item.create(id)) end end end for _, newItem in pairs(items) do 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.createNewOffer() local type = offerTypeList:getCurrentOption().text if type == 'Sell' then type = MarketAction.Sell else type = MarketAction.Buy end if not Market.isItemSelected() then return end local item = selectedItem.item local spriteId = item.ptr:getId() local piecePrice = piecePriceEdit:getValue() local totalPrice = totalPriceEdit:getValue() local amount = amountEdit:getValue() local anonymous = anonymous:isChecked() and 1 or 0 -- error checking local errorMsg = '' if type == MarketAction.Buy then if information.balance < ((piecePrice * amount) + fee) then errorMsg = errorMsg..'Not enough balance to create this offer.\n' end elseif type == MarketAction.Sell then if Market.depotContains(spriteId) < amount then errorMsg = errorMsg..'Not enough items in your depot to create this offer.\n' end end 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 local timeCheck = os.time() - lastCreatedOffer if timeCheck < offerExhaust[type] then local waitTime = math.ceil(offerExhaust[type] - timeCheck) errorMsg = errorMsg..'You must wait '.. waitTime ..' seconds before creating a new offer.\n' end if errorMsg ~= '' then displayInfoBox('Error', errorMsg) return end MarketProtocol.sendMarketCreateOffer(type, spriteId, amount, piecePrice, anonymous) lastCreatedOffer = os.time() Market.resetCreateOffer() end function Market.acceptMarketOffer(amount, timestamp, counter) if timestamp > 0 and amount > 0 then MarketProtocol.sendMarketAcceptOffer(timestamp, counter, amount) Market.refreshOffers() end end function Market.onItemBoxChecked(widget) if widget:isChecked() then if selectedItem.ref and widget ~= selectedItem.ref then selectedItem.ref:setChecked(false) -- temporary fix? end updateSelectedItem(widget) end end -- protocol callback functions function Market.onMarketEnter(depotItems, offers, balance, vocation) if not loaded then initMarketItems(MarketCategory.All) loaded = true end Market.clearSelectedItem() updateBalance(balance) information.totalOffers = offers local player = g_game.getLocalPlayer() if player then information.player = player end if vocation == -1 then if player then information.vocation = player:getVocation() end else -- vocation must be compatible with < 950 information.vocation = vocation end Market.loadDepotItems(depotItems) -- update the items widget to match depot items if Market.isItemSelected() then local spriteId = selectedItem.item.ptr:getId() MarketProtocol.silent(true) -- disable protocol messages Market.refreshItemsWidget(spriteId) MarketProtocol.silent(false) -- enable protocol messages else Market.refreshItemsWidget() end if table.empty(currentItems) then Market.loadMarketItems(MarketCategory.First) end -- 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 if g_game.isOnline() then marketWindow:lock() marketWindow:show() end end function Market.onMarketLeave() Market.close(false) end function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats) updateDetails(itemId, descriptions, purchaseStats, saleStats) end function Market.onMarketBrowse(offers) updateOffers(offers) end