Guest User

market.lua

a guest
Mar 27th, 2025
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 46.41 KB | None | 0 0
  1. --[[
  2. Finalizing Market:
  3. Note: Feel free to work on any area and submit
  4. it as a pull request from your git fork.
  5.  
  6. BeniS's Skype: benjiz69
  7.  
  8. List:
  9. * Add offer management:
  10. - Current Offers
  11. - Offer History
  12.  
  13. * Clean up the interface building
  14. - Add a new market interface file to handle building?
  15.  
  16. * Extend information features
  17. - Hover over offers for purchase information (balance after transaction, etc)
  18.  
  19. * Add items on
  20. otbToDatIds ->
  21. itemDefinitions ->
  22. defaultItems
  23. For them to be visual on market.
  24. ]]
  25.  
  26. Market = {}
  27.  
  28. local protocol = runinsandbox('marketprotocol')
  29.  
  30. -- First, update the ID mapping at the top of both files
  31. local otbToDatIds = {
  32. [2463] = 3357, --[plate armor] - Convert server ID (2463) to client ID (3357) for display
  33. [2464] = 3358, -- chain armor
  34. [2465] = 3359, -- brass armor
  35. [2466] = 3360 -- golden armor
  36. }
  37.  
  38. -- Add these tables at the top of market.lua
  39. local itemDefinitions = {
  40. [2463] = {name = "plate armor", category = 1},
  41. [2464] = {name = "chain armor", category = 1},
  42. [2465] = {name = "brass armor", category = 1},
  43. [2466] = {name = "golden armor", category = 1}
  44. -- Add more items as needed
  45. }
  46.  
  47. -- Helper function to get client ID for display
  48. local function getClientId(serverId)
  49. local clientId = otbToDatIds[serverId] or serverId
  50. g_logger.debug(string.format("Converting ID - Server: %d -> Client: %d", serverId, clientId))
  51. return clientId
  52. end
  53.  
  54. -- Add this helper function to convert client ID to server ID
  55. local function getServerIdFromClientId(clientId)
  56. -- Check each mapping for the client ID
  57. for serverId, clientIdMapping in pairs(otbToDatIds) do
  58. if clientIdMapping == clientId then
  59. return serverId
  60. end
  61. end
  62. return clientId -- Return original ID if no mapping found
  63. end
  64.  
  65. marketWindow = nil
  66. mainTabBar = nil
  67. displaysTabBar = nil
  68. offersTabBar = nil
  69. selectionTabBar = nil
  70.  
  71. marketOffersPanel = nil
  72. browsePanel = nil
  73. overviewPanel = nil
  74. itemOffersPanel = nil
  75. itemDetailsPanel = nil
  76. itemStatsPanel = nil
  77. myOffersPanel = nil
  78. currentOffersPanel = nil
  79. myCurrentOffersTab = nil
  80. myOfferHistoryTab = nil
  81. offerHistoryPanel = nil
  82. itemsPanel = nil
  83. selectedOffer = {}
  84. selectedMyOffer = {}
  85.  
  86. nameLabel = nil
  87. feeLabel = nil
  88. balanceLabel = nil
  89. totalPriceEdit = nil
  90. piecePriceEdit = nil
  91. amountEdit = nil
  92. searchEdit = nil
  93. radioItemSet = nil
  94. selectedItem = nil
  95. offerTypeList = nil
  96. categoryList = nil
  97. subCategoryList = nil
  98. slotFilterList = nil
  99. createOfferButton = nil
  100. buyButton = nil
  101. sellButton = nil
  102. anonymous = nil
  103. filterButtons = {}
  104.  
  105. buyOfferTable = nil
  106. sellOfferTable = nil
  107. detailsTable = nil
  108. buyStatsTable = nil
  109. sellStatsTable = nil
  110.  
  111. buyCancelButton = nil
  112. sellCancelButton = nil
  113. buyMyOfferTable = nil
  114. sellMyOfferTable = nil
  115. myOfferHistoryTabel = nil
  116.  
  117. offerExhaust = {}
  118. marketOffers = {}
  119. marketItems = {}
  120. marketItemNames = {}
  121. information = {}
  122. currentItems = {}
  123. lastCreatedOffer = 0
  124. fee = 0
  125. averagePrice = 0
  126. tibiaCoins = 0
  127.  
  128. loaded = false
  129.  
  130. local function isItemValid(item, category, searchFilter)
  131. if not item or not item.marketData then
  132. return false
  133. end
  134.  
  135. if not category then
  136. category = MarketCategory.All
  137. end
  138. if item.marketData.category ~= category and category ~= MarketCategory.All then
  139. return false
  140. end
  141.  
  142. -- filter item
  143. local slotFilter = false
  144. if slotFilterList:isEnabled() then
  145. slotFilter = getMarketSlotFilterId(slotFilterList:getCurrentOption().text)
  146. end
  147. local marketData = item.marketData
  148.  
  149. local filterVocation = filterButtons[MarketFilters.Vocation]:isChecked()
  150. local filterLevel = filterButtons[MarketFilters.Level]:isChecked()
  151. local filterDepot = filterButtons[MarketFilters.Depot]:isChecked()
  152.  
  153. if slotFilter then
  154. if slotFilter ~= 255 and item.thingType:getClothSlot() ~= slotFilter then
  155. return false
  156. end
  157. end
  158. local player = g_game.getLocalPlayer()
  159. if filterLevel and marketData.requiredLevel and player:getLevel() < marketData.requiredLevel then
  160. return false
  161. end
  162. if filterVocation and marketData.restrictVocation and marketData.restrictVocation > 0 then
  163. local voc = Bit.bit(information.vocation)
  164. if not Bit.hasBit(marketData.restrictVocation, voc) then
  165. return false
  166. end
  167. end
  168. if filterDepot and Market.getDepotCount(item.marketData.tradeAs) <= 0 then
  169. return false
  170. end
  171. if searchFilter then
  172. return marketData.name:lower():find(searchFilter)
  173. end
  174. return true
  175. end
  176.  
  177. local function clearItems()
  178. currentItems = {}
  179. Market.refreshItemsWidget()
  180. end
  181.  
  182. local function clearOffers()
  183. marketOffers[MarketAction.Buy] = {}
  184. marketOffers[MarketAction.Sell] = {}
  185. buyOfferTable:clearData()
  186. sellOfferTable:clearData()
  187. end
  188.  
  189. local function clearMyOffers()
  190. marketOffers[MarketAction.Buy] = {}
  191. marketOffers[MarketAction.Sell] = {}
  192. buyMyOfferTable:clearData()
  193. sellMyOfferTable:clearData()
  194. myOfferHistoryTabel:clearData()
  195. end
  196.  
  197. local function clearFilters()
  198. for _, filter in pairs(filterButtons) do
  199. if filter and filter:isChecked() ~= filter.default then
  200. filter:setChecked(filter.default)
  201. end
  202. end
  203. end
  204.  
  205. local function clearFee()
  206. feeLabel:setText('')
  207. fee = 20
  208. end
  209.  
  210. local function refreshTypeList()
  211. offerTypeList:clearOptions()
  212. offerTypeList:addOption('Buy')
  213.  
  214. if Market.isItemSelected() then
  215. if Market.getDepotCount(selectedItem.item.marketData.tradeAs) > 0 then
  216. offerTypeList:addOption('Sell')
  217. end
  218. end
  219. end
  220.  
  221. local function addOffer(offer, offerType)
  222. if not offer then
  223. return false
  224. end
  225. local id = offer:getId()
  226. local player = offer:getPlayer()
  227. local amount = offer:getAmount()
  228. local price = offer:getPrice()
  229. local timestamp = offer:getTimeStamp()
  230.  
  231. -- Get client ID from the offer
  232. local clientId = offer:getItem():getId()
  233. -- Convert to server ID for name lookup
  234. local serverId = getServerIdFromClientId(clientId)
  235.  
  236. -- Try to get the item name
  237. local itemName = nil
  238.  
  239. -- First try marketItemNames
  240. itemName = marketItemNames[serverId]
  241.  
  242. -- Then try itemDefinitions
  243. if not itemName and itemDefinitions[serverId] then
  244. itemName = itemDefinitions[serverId].name
  245. -- Cache it for future use
  246. marketItemNames[serverId] = itemName
  247. end
  248.  
  249. -- Fallback to a generic name if still not found
  250. if not itemName then
  251. itemName = "Unknown Item"
  252. end
  253.  
  254. g_logger.debug(string.format("Adding offer - Client ID: %d, Server ID: %d, Name: %s",
  255. clientId, serverId, itemName))
  256.  
  257. buyOfferTable:toggleSorting(false)
  258. sellOfferTable:toggleSorting(false)
  259.  
  260. buyMyOfferTable:toggleSorting(false)
  261. sellMyOfferTable:toggleSorting(false)
  262.  
  263. if amount < 1 then return false end
  264. if offerType == MarketAction.Buy then
  265. if offer.warn then
  266. buyOfferTable:setColumnStyle('OfferTableWarningColumn', true)
  267. end
  268.  
  269. local row = nil
  270. if offer.var == MarketRequest.MyOffers then
  271. row = buyMyOfferTable:addRow({
  272. {text = itemName},
  273. {text = comma_value(price*amount), sortvalue = price*amount},
  274. {text = comma_value(price), sortvalue = price},
  275. {text = amount},
  276. {text = string.gsub(os.date('%H:%M %d/%m/%y', timestamp), " ", " "), sortvalue = timestamp}
  277. })
  278. else
  279. row = buyOfferTable:addRow({
  280. {text = player},
  281. {text = amount},
  282. {text = comma_value(price*amount), sortvalue = price*amount},
  283. {text = comma_value(price), sortvalue = price},
  284. {text = string.gsub(os.date('%H:%M %d/%m/%y', timestamp), " ", " ")}
  285. })
  286. end
  287. row.ref = id
  288.  
  289. if offer.warn then
  290. row:setTooltip(tr('This offer is 25%% below the average market price'))
  291. buyOfferTable:setColumnStyle('OfferTableColumn', true)
  292. end
  293. else
  294. if offer.warn then
  295. sellOfferTable:setColumnStyle('OfferTableWarningColumn', true)
  296. end
  297.  
  298. local row = nil
  299. if offer.var == MarketRequest.MyOffers then
  300. row = sellMyOfferTable:addRow({
  301. {text = itemName},
  302. {text = comma_value(price*amount), sortvalue = price*amount},
  303. {text = comma_value(price), sortvalue = price},
  304. {text = amount},
  305. {text = string.gsub(os.date('%H:%M %d/%m/%y', timestamp), " ", " "), sortvalue = timestamp}
  306. })
  307. else
  308. row = sellOfferTable:addRow({
  309. {text = player},
  310. {text = amount},
  311. {text = comma_value(price*amount), sortvalue = price*amount},
  312. {text = comma_value(price), sortvalue = price},
  313. {text = string.gsub(os.date('%H:%M %d/%m/%y', timestamp), " ", " "), sortvalue = timestamp}
  314. })
  315. end
  316. row.ref = id
  317.  
  318. if offer.warn then
  319. row:setTooltip(tr('This offer is 25%% above the average market price'))
  320. sellOfferTable:setColumnStyle('OfferTableColumn', true)
  321. end
  322. end
  323.  
  324. buyOfferTable:toggleSorting(false)
  325. sellOfferTable:toggleSorting(false)
  326. buyOfferTable:sort()
  327. sellOfferTable:sort()
  328.  
  329. buyMyOfferTable:toggleSorting(false)
  330. sellMyOfferTable:toggleSorting(false)
  331. buyMyOfferTable:sort()
  332. sellMyOfferTable:sort()
  333.  
  334. return true
  335. end
  336.  
  337. local function mergeOffer(offer)
  338. if not offer then
  339. return false
  340. end
  341.  
  342. local id = offer:getId()
  343. local offerType = offer:getType()
  344. local amount = offer:getAmount()
  345. local replaced = false
  346.  
  347. if offerType == MarketAction.Buy then
  348. if averagePrice > 0 then
  349. offer.warn = offer:getPrice() <= averagePrice - math.floor(averagePrice / 4)
  350. end
  351.  
  352. for i = 1, #marketOffers[MarketAction.Buy] do
  353. local o = marketOffers[MarketAction.Buy][i]
  354. -- replace existing offer
  355. if o:isEqual(id) then
  356. marketOffers[MarketAction.Buy][i] = offer
  357. replaced = true
  358. end
  359. end
  360. if not replaced then
  361. table.insert(marketOffers[MarketAction.Buy], offer)
  362. end
  363. else
  364. if averagePrice > 0 then
  365. offer.warn = offer:getPrice() >= averagePrice + math.floor(averagePrice / 4)
  366. end
  367.  
  368. for i = 1, #marketOffers[MarketAction.Sell] do
  369. local o = marketOffers[MarketAction.Sell][i]
  370. -- replace existing offer
  371. if o:isEqual(id) then
  372. marketOffers[MarketAction.Sell][i] = offer
  373. replaced = true
  374. end
  375. end
  376. if not replaced then
  377. table.insert(marketOffers[MarketAction.Sell], offer)
  378. end
  379. end
  380. return true
  381. end
  382.  
  383. local function updateOffers(offers)
  384. if not buyOfferTable or not sellOfferTable then
  385. return
  386. end
  387.  
  388. balanceLabel:setColor('#bbbbbb')
  389. selectedOffer[MarketAction.Buy] = nil
  390. selectedOffer[MarketAction.Sell] = nil
  391.  
  392. selectedMyOffer[MarketAction.Buy] = nil
  393. selectedMyOffer[MarketAction.Sell] = nil
  394.  
  395. -- clear existing offer data
  396. buyOfferTable:clearData()
  397. buyOfferTable:setSorting(4, TABLE_SORTING_DESC)
  398. sellOfferTable:clearData()
  399. sellOfferTable:setSorting(4, TABLE_SORTING_ASC)
  400.  
  401. sellButton:setEnabled(false)
  402. buyButton:setEnabled(false)
  403.  
  404. buyCancelButton:setEnabled(false)
  405. sellCancelButton:setEnabled(false)
  406.  
  407. for _, offer in pairs(offers) do
  408. mergeOffer(offer)
  409. end
  410. for type, offers in pairs(marketOffers) do
  411. for i = 1, #offers do
  412. addOffer(offers[i], type)
  413. end
  414. end
  415. end
  416.  
  417. local function updateHistoryOffers(offers)
  418. myOfferHistoryTabel:toggleSorting(false)
  419. myOfferHistoryTabel:clearData()
  420.  
  421. for _, offer in ipairs(offers) do
  422. local offerType = offer:getType()
  423. local clientId = offer:getItem():getId()
  424. -- Convert client ID to server ID for name lookup
  425. local serverId = getServerIdFromClientId(clientId)
  426. local amount = offer:getAmount()
  427. local price = offer:getPrice()
  428. local timestamp = offer:getTimeStamp()
  429.  
  430. -- Get item name using the same system as addOffer
  431. local itemName = nil
  432.  
  433. -- First try marketItemNames
  434. itemName = marketItemNames[serverId]
  435.  
  436. -- Then try itemDefinitions
  437. if not itemName and itemDefinitions[serverId] then
  438. itemName = itemDefinitions[serverId].name
  439. -- Cache it for future use
  440. marketItemNames[serverId] = itemName
  441. end
  442.  
  443. -- Fallback to a generic name if still not found
  444. if not itemName then
  445. itemName = "Unknown Item"
  446. end
  447.  
  448. g_logger.debug(string.format("History offer - Client ID: %d, Server ID: %d, Name: %s",
  449. clientId, serverId, itemName))
  450.  
  451. local offerTypeName = offerType == MarketAction.Buy and "Buy" or "Sell"
  452.  
  453. local row = myOfferHistoryTabel:addRow({
  454. {text = offerTypeName},
  455. {text = itemName},
  456. {text = comma_value(price * amount), sortvalue = price * amount},
  457. {text = comma_value(price), sortvalue = price},
  458. {text = amount},
  459. {text = string.gsub(os.date('%H:%M %d/%m/%y', timestamp), " ", " "), sortvalue = timestamp}
  460. })
  461. end
  462.  
  463. myOfferHistoryTabel:toggleSorting(false)
  464. myOfferHistoryTabel:sort()
  465. end
  466.  
  467. local function updateDetails(itemId, descriptions, purchaseStats, saleStats)
  468. if not selectedItem then
  469. return
  470. end
  471.  
  472. -- update item details
  473. detailsTable:clearData()
  474. for k, desc in pairs(descriptions) do
  475. local columns = {
  476. {text = getMarketDescriptionName(desc[1])..':'},
  477. {text = desc[2]}
  478. }
  479. detailsTable:addRow(columns)
  480. end
  481.  
  482. -- update sale item statistics
  483. sellStatsTable:clearData()
  484. if table.empty(saleStats) then
  485. sellStatsTable:addRow({{text = 'No information'}})
  486. else
  487. local offerAmount = 0
  488. local transactions, totalPrice, highestPrice, lowestPrice = 0, 0, 0, 0
  489. for _, stat in pairs(saleStats) do
  490. if not stat:isNull() then
  491. offerAmount = offerAmount + 1
  492. transactions = transactions + stat:getTransactions()
  493. totalPrice = totalPrice + stat:getTotalPrice()
  494. local newHigh = stat:getHighestPrice()
  495. if newHigh > highestPrice then
  496. highestPrice = newHigh
  497. end
  498. local newLow = stat:getLowestPrice()
  499. -- ?? getting '0xffffffff' result from lowest price in 9.60 cipsoft
  500. if (lowestPrice == 0 or newLow < lowestPrice) and newLow ~= 0xffffffff then
  501. lowestPrice = newLow
  502. end
  503. end
  504. end
  505.  
  506. if offerAmount >= 5 and transactions >= 10 then
  507. averagePrice = math.round(totalPrice / transactions)
  508. else
  509. averagePrice = 0
  510. end
  511.  
  512. sellStatsTable:addRow({{text = 'Total Transations:'}, {text = transactions}})
  513. sellStatsTable:addRow({{text = 'Highest Price:'}, {text = highestPrice}})
  514.  
  515. if totalPrice > 0 and transactions > 0 then
  516. sellStatsTable:addRow({{text = 'Average Price:'},
  517. {text = math.floor(totalPrice/transactions)}})
  518. else
  519. sellStatsTable:addRow({{text = 'Average Price:'}, {text = 0}})
  520. end
  521.  
  522. sellStatsTable:addRow({{text = 'Lowest Price:'}, {text = lowestPrice}})
  523. end
  524.  
  525. -- update buy item statistics
  526. buyStatsTable:clearData()
  527. if table.empty(purchaseStats) then
  528. buyStatsTable:addRow({{text = 'No information'}})
  529. else
  530. local transactions, totalPrice, highestPrice, lowestPrice = 0, 0, 0, 0
  531. for _, stat in pairs(purchaseStats) do
  532. if not stat:isNull() then
  533. transactions = transactions + stat:getTransactions()
  534. totalPrice = totalPrice + stat:getTotalPrice()
  535. local newHigh = stat:getHighestPrice()
  536. if newHigh > highestPrice then
  537. highestPrice = newHigh
  538. end
  539. local newLow = stat:getLowestPrice()
  540. -- ?? getting '0xffffffff' result from lowest price in 9.60 cipsoft
  541. if (lowestPrice == 0 or newLow < lowestPrice) and newLow ~= 0xffffffff then
  542. lowestPrice = newLow
  543. end
  544. end
  545. end
  546.  
  547. buyStatsTable:addRow({{text = 'Total Transations:'},{text = transactions}})
  548. buyStatsTable:addRow({{text = 'Highest Price:'}, {text = highestPrice}})
  549.  
  550. if totalPrice > 0 and transactions > 0 then
  551. buyStatsTable:addRow({{text = 'Average Price:'},
  552. {text = math.floor(totalPrice/transactions)}})
  553. else
  554. buyStatsTable:addRow({{text = 'Average Price:'}, {text = 0}})
  555. end
  556.  
  557. buyStatsTable:addRow({{text = 'Lowest Price:'}, {text = lowestPrice}})
  558. end
  559. end
  560.  
  561. local function updateSelectedItem(widget)
  562. selectedItem.item = widget.item
  563. selectedItem.ref = widget
  564.  
  565. Market.resetCreateOffer()
  566. if Market.isItemSelected() then
  567. local serverId = selectedItem.item.marketData.tradeAs
  568. local clientId = getClientId(serverId)
  569.  
  570. local displayItem = Item.create(clientId) -- Create with client ID
  571. selectedItem:setItem(displayItem)
  572.  
  573. g_logger.debug(string.format("Selected item - Server ID: %d, Client ID: %d",
  574. serverId, clientId))
  575.  
  576. nameLabel:setText(selectedItem.item.marketData.name)
  577. clearOffers()
  578.  
  579. Market.enableCreateOffer(true)
  580. MarketProtocol.sendMarketBrowse(serverId) -- Use server ID for market operations
  581. else
  582. Market.clearSelectedItem()
  583. end
  584. end
  585.  
  586. local function updateBalance(balance)
  587. local balance = tonumber(balance)
  588. if not balance then
  589. return
  590. end
  591.  
  592. if balance < 0 then balance = 0 end
  593. information.balance = balance
  594.  
  595. balanceLabel:setText('Balance: '.. comma_value(balance) ..' gold')
  596. balanceLabel:resizeToText()
  597. end
  598.  
  599. local function updateFee(price, amount)
  600. fee = math.ceil(price / 100 * amount)
  601. if fee < 20 then
  602. fee = 20
  603. elseif fee > 1000 then
  604. fee = 1000
  605. end
  606. feeLabel:setText('Fee: '.. comma_value(fee))
  607. feeLabel:resizeToText()
  608. end
  609.  
  610. local function destroyAmountWindow()
  611. if amountWindow then
  612. amountWindow:destroy()
  613. amountWindow = nil
  614. end
  615. end
  616.  
  617. local function cancelMyOffer(actionType)
  618. local offer = selectedMyOffer[actionType]
  619. MarketProtocol.sendMarketCancelOffer(offer:getTimeStamp(), offer:getCounter())
  620. Market.refreshMyOffers()
  621. end
  622.  
  623. local function openAmountWindow(callback, actionType, actionText)
  624. if not Market.isOfferSelected(actionType) then
  625. return
  626. end
  627.  
  628. amountWindow = g_ui.createWidget('AmountWindow', rootWidget)
  629. amountWindow:lock()
  630.  
  631. local offer = selectedOffer[actionType]
  632. local serverId = offer:getItem():getId()
  633. local clientId = getClientId(serverId) -- Convert to client ID for display
  634.  
  635. local maximum = offer:getAmount()
  636. if actionType == MarketAction.Sell then
  637. local depot = Market.getDepotCount(serverId) -- Use server ID for depot check
  638. if maximum > depot then
  639. maximum = depot
  640. end
  641. else
  642. maximum = math.min(maximum, math.floor(information.balance / offer:getPrice()))
  643. end
  644.  
  645. if offer:getItem():isStackable() then
  646. maximum = math.min(maximum, MarketMaxAmountStackable)
  647. else
  648. maximum = math.min(maximum, MarketMaxAmount)
  649. end
  650.  
  651. local itembox = amountWindow:getChildById('item')
  652. itembox:setItemId(clientId) -- Use client ID for display
  653. g_logger.debug(string.format("Amount window item - Server ID: %d, Client ID: %d",
  654. serverId, clientId))
  655.  
  656. local scrollbar = amountWindow:getChildById('amountScrollBar')
  657. scrollbar:setText(comma_value(offer:getPrice()) ..'gp')
  658.  
  659. scrollbar.onValueChange = function(widget, value)
  660. widget:setText(comma_value(value*offer:getPrice())..'gp')
  661. itembox:setText(comma_value(value))
  662. end
  663. scrollbar:setRange(1, maximum)
  664. scrollbar:setValue(1)
  665.  
  666. local okButton = amountWindow:getChildById('buttonOk')
  667. if actionText then
  668. okButton:setText(actionText)
  669. end
  670.  
  671. local okFunc = function()
  672. local counter = offer:getCounter()
  673. local timestamp = offer:getTimeStamp()
  674. callback(scrollbar:getValue(), timestamp, counter)
  675. destroyAmountWindow()
  676. end
  677.  
  678. local cancelButton = amountWindow:getChildById('buttonCancel')
  679. local cancelFunc = function()
  680. destroyAmountWindow()
  681. end
  682.  
  683. amountWindow.onEnter = okFunc
  684. amountWindow.onEscape = cancelFunc
  685.  
  686. okButton.onClick = okFunc
  687. cancelButton.onClick = cancelFunc
  688. end
  689.  
  690. local function onSelectSellOffer(table, selectedRow, previousSelectedRow)
  691. updateBalance()
  692. for _, offer in pairs(marketOffers[MarketAction.Sell]) do
  693. if offer:isEqual(selectedRow.ref) then
  694. selectedOffer[MarketAction.Buy] = offer
  695. end
  696. end
  697.  
  698. local offer = selectedOffer[MarketAction.Buy]
  699. if offer then
  700. local price = offer:getPrice()
  701. if price > information.balance then
  702. balanceLabel:setColor('#b22222') -- red
  703. buyButton:setEnabled(false)
  704. else
  705. local slice = (information.balance / 2)
  706. if (price/slice) * 100 <= 40 then
  707. color = '#008b00' -- green
  708. elseif (price/slice) * 100 <= 70 then
  709. color = '#eec900' -- yellow
  710. else
  711. color = '#ee9a00' -- orange
  712. end
  713. balanceLabel:setColor(color)
  714. buyButton:setEnabled(true)
  715. end
  716. end
  717. end
  718.  
  719. local function onSelectBuyOffer(table, selectedRow, previousSelectedRow)
  720. updateBalance()
  721. for _, offer in pairs(marketOffers[MarketAction.Buy]) do
  722. if offer:isEqual(selectedRow.ref) then
  723. selectedOffer[MarketAction.Sell] = offer
  724. if Market.getDepotCount(offer:getItem():getId()) > 0 then
  725. sellButton:setEnabled(true)
  726. else
  727. sellButton:setEnabled(false)
  728. end
  729. end
  730. end
  731. end
  732.  
  733. local function onSelectMyBuyOffer(table, selectedRow, previousSelectedRow)
  734. for _, offer in pairs(marketOffers[MarketAction.Buy]) do
  735. if offer:isEqual(selectedRow.ref) then
  736. selectedMyOffer[MarketAction.Buy] = offer
  737. buyCancelButton:setEnabled(true)
  738. end
  739. end
  740. end
  741.  
  742. local function onSelectMySellOffer(table, selectedRow, previousSelectedRow)
  743. for _, offer in pairs(marketOffers[MarketAction.Sell]) do
  744. if offer:isEqual(selectedRow.ref) then
  745. selectedMyOffer[MarketAction.Sell] = offer
  746. sellCancelButton:setEnabled(true)
  747. end
  748. end
  749. end
  750.  
  751. local function onChangeCategory(combobox, option)
  752. local id = getMarketCategoryId(option)
  753. if id == MarketCategory.MetaWeapons then
  754. -- enable and load weapons filter/items
  755. subCategoryList:setEnabled(true)
  756. slotFilterList:setEnabled(true)
  757. local subId = getMarketCategoryId(subCategoryList:getCurrentOption().text)
  758. Market.loadMarketItems(subId)
  759. else
  760. subCategoryList:setEnabled(false)
  761. slotFilterList:setEnabled(false)
  762. Market.loadMarketItems(id) -- load standard filter
  763. end
  764. end
  765.  
  766. local function onChangeSubCategory(combobox, option)
  767. Market.loadMarketItems(getMarketCategoryId(option))
  768. slotFilterList:clearOptions()
  769.  
  770. local subId = getMarketCategoryId(subCategoryList:getCurrentOption().text)
  771. local slots = MarketCategoryWeapons[subId].slots
  772. for _, slot in pairs(slots) do
  773. if table.haskey(MarketSlotFilters, slot) then
  774. slotFilterList:addOption(MarketSlotFilters[slot])
  775. end
  776. end
  777. slotFilterList:setEnabled(true)
  778. end
  779.  
  780. local function onChangeSlotFilter(combobox, option)
  781. Market.updateCurrentItems()
  782. end
  783.  
  784. local function onChangeOfferType(combobox, option)
  785. local item = selectedItem.item
  786. local maximum = item.thingType:isStackable() and MarketMaxAmountStackable or MarketMaxAmount
  787.  
  788. if option == 'Sell' then
  789. maximum = math.min(maximum, Market.getDepotCount(item.marketData.tradeAs))
  790. amountEdit:setMaximum(maximum)
  791. else
  792. amountEdit:setMaximum(maximum)
  793. end
  794. end
  795.  
  796. local function onTotalPriceChange()
  797. local amount = amountEdit:getValue()
  798. local totalPrice = totalPriceEdit:getValue()
  799. local piecePrice = math.floor(totalPrice/amount)
  800.  
  801. piecePriceEdit:setValue(piecePrice, true)
  802. if Market.isItemSelected() then
  803. updateFee(piecePrice, amount)
  804. end
  805. end
  806.  
  807. local function onPiecePriceChange()
  808. local amount = amountEdit:getValue()
  809. local totalPrice = totalPriceEdit:getValue()
  810. local piecePrice = piecePriceEdit:getValue()
  811.  
  812. totalPriceEdit:setValue(piecePrice*amount, true)
  813. if Market.isItemSelected() then
  814. updateFee(piecePrice, amount)
  815. end
  816. end
  817.  
  818. local function onAmountChange()
  819. local amount = amountEdit:getValue()
  820. local piecePrice = piecePriceEdit:getValue()
  821. local totalPrice = piecePrice * amount
  822.  
  823. totalPriceEdit:setValue(piecePrice*amount, true)
  824. if Market.isItemSelected() then
  825. updateFee(piecePrice, amount)
  826. end
  827. end
  828.  
  829. local function onMarketMessage(messageMode, message)
  830. Market.displayMessage(message)
  831. end
  832.  
  833. local function initMarketItems(items)
  834. for c = MarketCategory.First, MarketCategory.Last do
  835. marketItems[c] = {}
  836. end
  837. marketItemNames = {}
  838.  
  839. -- Initialize marketItemNames with defined items
  840. for serverId, itemDef in pairs(itemDefinitions) do
  841. marketItemNames[serverId] = itemDef.name
  842. end
  843.  
  844. -- Function to process a single item entry
  845. local function processItem(entry)
  846. local serverId = entry.id
  847. local displayItem = Item.create(serverId)
  848. local thingType = g_things.getThingType(serverId, ThingCategoryItem)
  849.  
  850. if displayItem and thingType then
  851. -- Store the name mapping
  852. marketItemNames[serverId] = entry.name
  853.  
  854. -- Create market item
  855. local marketItem = {
  856. displayItem = displayItem,
  857. thingType = thingType,
  858. marketData = {
  859. name = entry.name,
  860. category = entry.category,
  861. requiredLevel = 0,
  862. restrictVocation = 0,
  863. showAs = serverId,
  864. tradeAs = serverId
  865. }
  866. }
  867.  
  868. if marketItems[entry.category] then
  869. g_logger.debug(string.format("Adding market item - Server ID: %d, Name: %s",
  870. serverId, entry.name))
  871. table.insert(marketItems[entry.category], marketItem)
  872. end
  873. end
  874. end
  875.  
  876. -- Process provided items
  877. if items and #items > 0 then
  878. for _, entry in ipairs(items) do
  879. processItem(entry)
  880. end
  881. else
  882. -- Process default items
  883. local defaultItems = {
  884. {
  885. id = 2463,
  886. category = 1,
  887. name = "plate armor"
  888. },
  889. {
  890. id = 2464,
  891. category = 1,
  892. name = "chain armor"
  893. },
  894. {
  895. id = 2465,
  896. category = 1,
  897. name = "brass armor"
  898. },
  899. {
  900. id = 2466,
  901. category = 1,
  902. name = "golden armor"
  903. }
  904. -- Add more defaults if needed
  905. }
  906.  
  907. for _, entry in ipairs(defaultItems) do
  908. processItem(entry)
  909. end
  910. end
  911.  
  912. Market.updateCategories()
  913. end
  914.  
  915. local function initInterface()
  916. -- TODO: clean this up
  917. -- setup main tabs
  918. mainTabBar = marketWindow:getChildById('mainTabBar')
  919. mainTabBar:setContentWidget(marketWindow:getChildById('mainTabContent'))
  920.  
  921. -- setup 'Market Offer' section tabs
  922. marketOffersPanel = g_ui.loadUI('ui/marketoffers')
  923. mainTabBar:addTab(tr('Market Offers'), marketOffersPanel)
  924.  
  925. selectionTabBar = marketOffersPanel:getChildById('leftTabBar')
  926. selectionTabBar:setContentWidget(marketOffersPanel:getChildById('leftTabContent'))
  927.  
  928. browsePanel = g_ui.loadUI('ui/marketoffers/browse')
  929. selectionTabBar:addTab(tr('Browse'), browsePanel)
  930.  
  931. -- Currently not used
  932. -- "Reserved for more functionality later"
  933. --overviewPanel = g_ui.loadUI('ui/marketoffers/overview')
  934. --selectionTabBar:addTab(tr('Overview'), overviewPanel)
  935.  
  936. displaysTabBar = marketOffersPanel:getChildById('rightTabBar')
  937. displaysTabBar:setContentWidget(marketOffersPanel:getChildById('rightTabContent'))
  938.  
  939. itemStatsPanel = g_ui.loadUI('ui/marketoffers/itemstats')
  940. displaysTabBar:addTab(tr('Statistics'), itemStatsPanel)
  941.  
  942. itemDetailsPanel = g_ui.loadUI('ui/marketoffers/itemdetails')
  943. displaysTabBar:addTab(tr('Details'), itemDetailsPanel)
  944.  
  945. itemOffersPanel = g_ui.loadUI('ui/marketoffers/itemoffers')
  946. displaysTabBar:addTab(tr('Offers'), itemOffersPanel)
  947. displaysTabBar:selectTab(displaysTabBar:getTab(tr('Offers')))
  948.  
  949. -- setup 'My Offer' section tabs
  950. myOffersPanel = g_ui.loadUI('ui/myoffers')
  951. local myOffersTab = mainTabBar:addTab(tr('My Offers'), myOffersPanel)
  952.  
  953. offersTabBar = myOffersPanel:getChildById('offersTabBar')
  954. offersTabBar:setContentWidget(myOffersPanel:getChildById('offersTabContent'))
  955.  
  956. currentOffersPanel = g_ui.loadUI('ui/myoffers/currentoffers')
  957. myCurrentOffersTab = offersTabBar:addTab(tr('Current Offers'), currentOffersPanel)
  958.  
  959. offerHistoryPanel = g_ui.loadUI('ui/myoffers/offerhistory')
  960. myOfferHistoryTab = offersTabBar:addTab(tr('Offer History'), offerHistoryPanel)
  961.  
  962. balanceLabel = marketWindow:getChildById('balanceLabel')
  963.  
  964. mainTabBar.onTabChange = function(widget, tab)
  965. if tab == myOffersTab then
  966. local ctab = offersTabBar:getCurrentTab()
  967. if ctab == myCurrentOffersTab then
  968. Market.refreshMyOffers()
  969. elseif ctab == myOfferHistoryTab then
  970. Market.refreshMyOffersHistory()
  971. end
  972. else
  973. Market.refreshOffers()
  974. end
  975. end
  976.  
  977. offersTabBar.onTabChange = function(widget, tab)
  978. if tab == myCurrentOffersTab then
  979. Market.refreshMyOffers()
  980. elseif tab == myOfferHistoryTab then
  981. Market.refreshMyOffersHistory()
  982. end
  983. end
  984.  
  985. -- setup offers
  986. buyButton = itemOffersPanel:getChildById('buyButton')
  987. buyButton.onClick = function() openAmountWindow(Market.acceptMarketOffer, MarketAction.Buy, 'Buy') end
  988.  
  989. sellButton = itemOffersPanel:getChildById('sellButton')
  990. sellButton.onClick = function() openAmountWindow(Market.acceptMarketOffer, MarketAction.Sell, 'Sell') end
  991.  
  992. -- setup selected item
  993. nameLabel = marketOffersPanel:getChildById('nameLabel')
  994. selectedItem = marketOffersPanel:getChildById('selectedItem')
  995.  
  996. -- setup create new offer
  997. totalPriceEdit = marketOffersPanel:getChildById('totalPriceEdit')
  998. piecePriceEdit = marketOffersPanel:getChildById('piecePriceEdit')
  999. amountEdit = marketOffersPanel:getChildById('amountEdit')
  1000. feeLabel = marketOffersPanel:getChildById('feeLabel')
  1001. totalPriceEdit.onValueChange = onTotalPriceChange
  1002. piecePriceEdit.onValueChange = onPiecePriceChange
  1003. amountEdit.onValueChange = onAmountChange
  1004.  
  1005. offerTypeList = marketOffersPanel:getChildById('offerTypeComboBox')
  1006. offerTypeList.onOptionChange = onChangeOfferType
  1007.  
  1008. anonymous = marketOffersPanel:getChildById('anonymousCheckBox')
  1009. createOfferButton = marketOffersPanel:getChildById('createOfferButton')
  1010. createOfferButton.onClick = Market.createNewOffer
  1011. Market.enableCreateOffer(false)
  1012.  
  1013. -- setup filters
  1014. filterButtons[MarketFilters.Vocation] = browsePanel:getChildById('filterVocation')
  1015. filterButtons[MarketFilters.Level] = browsePanel:getChildById('filterLevel')
  1016. filterButtons[MarketFilters.Depot] = browsePanel:getChildById('filterDepot')
  1017. filterButtons[MarketFilters.SearchAll] = browsePanel:getChildById('filterSearchAll')
  1018.  
  1019. -- set filter default values
  1020. clearFilters()
  1021.  
  1022. -- hook filters
  1023. for _, filter in pairs(filterButtons) do
  1024. filter.onCheckChange = Market.updateCurrentItems
  1025. end
  1026.  
  1027. searchEdit = browsePanel:getChildById('searchEdit')
  1028. categoryList = browsePanel:getChildById('categoryComboBox')
  1029. subCategoryList = browsePanel:getChildById('subCategoryComboBox')
  1030. slotFilterList = browsePanel:getChildById('slotComboBox')
  1031.  
  1032. slotFilterList:addOption(MarketSlotFilters[255])
  1033. slotFilterList:setEnabled(false)
  1034.  
  1035. Market.updateCategories()
  1036.  
  1037. -- hook item filters
  1038. categoryList.onOptionChange = onChangeCategory
  1039. subCategoryList.onOptionChange = onChangeSubCategory
  1040. slotFilterList.onOptionChange = onChangeSlotFilter
  1041.  
  1042. -- setup tables
  1043. buyOfferTable = itemOffersPanel:recursiveGetChildById('buyingTable')
  1044. sellOfferTable = itemOffersPanel:recursiveGetChildById('sellingTable')
  1045. detailsTable = itemDetailsPanel:recursiveGetChildById('detailsTable')
  1046. buyStatsTable = itemStatsPanel:recursiveGetChildById('buyStatsTable')
  1047. sellStatsTable = itemStatsPanel:recursiveGetChildById('sellStatsTable')
  1048. buyOfferTable.onSelectionChange = onSelectBuyOffer
  1049. sellOfferTable.onSelectionChange = onSelectSellOffer
  1050.  
  1051. -- setup my offers
  1052. buyMyOfferTable = currentOffersPanel:recursiveGetChildById('myBuyingTable')
  1053. sellMyOfferTable = currentOffersPanel:recursiveGetChildById('mySellingTable')
  1054. myOfferHistoryTabel = offerHistoryPanel:recursiveGetChildById('myHistoryTable')
  1055.  
  1056. buyMyOfferTable.onSelectionChange = onSelectMyBuyOffer
  1057. sellMyOfferTable.onSelectionChange = onSelectMySellOffer
  1058.  
  1059. buyCancelButton = currentOffersPanel:getChildById('buyCancelButton')
  1060. buyCancelButton.onClick = function() cancelMyOffer(MarketAction.Buy) end
  1061.  
  1062. sellCancelButton = currentOffersPanel:getChildById('sellCancelButton')
  1063. sellCancelButton.onClick = function() cancelMyOffer(MarketAction.Sell) end
  1064.  
  1065.  
  1066. buyStatsTable:setColumnWidth({120, 270})
  1067. sellStatsTable:setColumnWidth({120, 270})
  1068. detailsTable:setColumnWidth({80, 330})
  1069.  
  1070. buyOfferTable:setSorting(4, TABLE_SORTING_DESC)
  1071. sellOfferTable:setSorting(4, TABLE_SORTING_ASC)
  1072.  
  1073. buyMyOfferTable:setSorting(3, TABLE_SORTING_DESC)
  1074. sellMyOfferTable:setSorting(3, TABLE_SORTING_DESC)
  1075. myOfferHistoryTabel:setSorting(6, TABLE_SORTING_DESC)
  1076. end
  1077.  
  1078. function init()
  1079. g_ui.importStyle('market')
  1080. g_ui.importStyle('ui/general/markettabs')
  1081. g_ui.importStyle('ui/general/marketbuttons')
  1082. g_ui.importStyle('ui/general/marketcombobox')
  1083. g_ui.importStyle('ui/general/amountwindow')
  1084.  
  1085. offerExhaust[MarketAction.Sell] = 10
  1086. offerExhaust[MarketAction.Buy] = 20
  1087.  
  1088. registerMessageMode(MessageModes.Market, onMarketMessage)
  1089.  
  1090. protocol.initProtocol()
  1091. connect(g_game, { onGameEnd = Market.reset })
  1092. connect(g_game, { onGameEnd = Market.close })
  1093. connect(g_game, { onGameStart = Market.updateCategories })
  1094. connect(g_game, { onCoinBalance = Market.onCoinBalance })
  1095.  
  1096. marketWindow = g_ui.createWidget('MarketWindow', rootWidget)
  1097. marketWindow:hide()
  1098.  
  1099. initInterface() -- build interface
  1100. end
  1101.  
  1102. function terminate()
  1103. Market.close()
  1104.  
  1105. unregisterMessageMode(MessageModes.Market, onMarketMessage)
  1106.  
  1107. protocol.terminateProtocol()
  1108. disconnect(g_game, { onGameEnd = Market.reset })
  1109. disconnect(g_game, { onGameEnd = Market.close })
  1110. disconnect(g_game, { onGameStart = Market.updateCategories })
  1111. disconnect(g_game, { onCoinBalance = Market.onCoinBalance })
  1112.  
  1113. destroyAmountWindow()
  1114. marketWindow:destroy()
  1115.  
  1116. Market = nil
  1117. end
  1118.  
  1119. function Market.reset()
  1120. balanceLabel:setColor('#bbbbbb')
  1121. categoryList:setCurrentOption(getMarketCategoryName(MarketCategory.First))
  1122. searchEdit:setText('')
  1123. clearFilters()
  1124. clearMyOffers()
  1125. if not table.empty(information) then
  1126. Market.updateCurrentItems()
  1127. end
  1128. end
  1129.  
  1130. function Market.updateCategories()
  1131. categoryList:clearOptions()
  1132. subCategoryList:clearOptions()
  1133.  
  1134. local categories = {}
  1135. local addedCategories = {}
  1136. for _, c in ipairs(g_things.getMarketCategories()) do
  1137. table.insert(categories, getMarketCategoryName(c) or "Unknown")
  1138. addedCategories[c] = true
  1139. end
  1140. for c, items in ipairs(marketItems) do
  1141. if #items > 0 and not addedCategories[c] then
  1142. table.insert(categories, getMarketCategoryName(c) or "Unknown")
  1143. addedCategories[c] = true
  1144. end
  1145. end
  1146.  
  1147. table.sort(categories)
  1148. for _, c in ipairs(categories) do
  1149. categoryList:addOption(c)
  1150. end
  1151.  
  1152. for i = MarketCategory.Ammunition, MarketCategory.WandsRods do
  1153. subCategoryList:addOption(getMarketCategoryName(i))
  1154. end
  1155.  
  1156. categoryList:addOption(getMarketCategoryName(255)) -- meta weapons
  1157. categoryList:setCurrentOption(getMarketCategoryName(MarketCategory.First))
  1158. subCategoryList:setEnabled(false)
  1159. end
  1160.  
  1161. function Market.displayMessage(message)
  1162. if marketWindow:isHidden() then return end
  1163.  
  1164. local infoBox = displayInfoBox(tr('Market Error'), message)
  1165. infoBox:lock()
  1166. end
  1167.  
  1168. function Market.clearSelectedItem()
  1169. if Market.isItemSelected() then
  1170. Market.resetCreateOffer(true)
  1171. offerTypeList:clearOptions()
  1172. offerTypeList:setText('Please Select')
  1173. offerTypeList:setEnabled(false)
  1174.  
  1175. clearOffers()
  1176. radioItemSet:selectWidget(nil)
  1177. nameLabel:setText('No item selected.')
  1178. selectedItem:setItem(nil)
  1179. selectedItem.item = nil
  1180. selectedItem.ref:setChecked(false)
  1181. selectedItem.ref = nil
  1182.  
  1183. detailsTable:clearData()
  1184. buyStatsTable:clearData()
  1185. sellStatsTable:clearData()
  1186.  
  1187. Market.enableCreateOffer(false)
  1188. end
  1189. end
  1190.  
  1191. function Market.isItemSelected()
  1192. return selectedItem and selectedItem.item
  1193. end
  1194.  
  1195. function Market.isOfferSelected(type)
  1196. return selectedOffer[type] and not selectedOffer[type]:isNull()
  1197. end
  1198.  
  1199. function Market.getDepotCount(itemId)
  1200. if not information.depotItems then
  1201. return 0
  1202. end
  1203. return information.depotItems[itemId] or 0
  1204. end
  1205.  
  1206. function Market.enableCreateOffer(enable)
  1207. offerTypeList:setEnabled(enable)
  1208. totalPriceEdit:setEnabled(enable)
  1209. piecePriceEdit:setEnabled(enable)
  1210. amountEdit:setEnabled(enable)
  1211. anonymous:setEnabled(enable)
  1212. createOfferButton:setEnabled(enable)
  1213.  
  1214. local prevAmountButton = marketOffersPanel:recursiveGetChildById('prevAmountButton')
  1215. local nextAmountButton = marketOffersPanel:recursiveGetChildById('nextAmountButton')
  1216.  
  1217. prevAmountButton:setEnabled(enable)
  1218. nextAmountButton:setEnabled(enable)
  1219. end
  1220.  
  1221. function Market.close(notify)
  1222. if notify == nil then notify = true end
  1223. if not marketWindow:isHidden() then
  1224. marketWindow:hide()
  1225. marketWindow:unlock()
  1226. modules.game_interface.getRootPanel():focus()
  1227. Market.clearSelectedItem()
  1228. Market.reset()
  1229. if notify then
  1230. MarketProtocol.sendMarketLeave()
  1231. end
  1232. end
  1233. end
  1234.  
  1235. function Market.incrementAmount()
  1236. amountEdit:setValue(amountEdit:getValue() + 1)
  1237. end
  1238.  
  1239. function Market.decrementAmount()
  1240. amountEdit:setValue(amountEdit:getValue() - 1)
  1241. end
  1242.  
  1243. function Market.updateCurrentItems()
  1244. if not categoryList or not categoryList:getCurrentOption() then
  1245. return
  1246. end
  1247. local id = getMarketCategoryId(categoryList:getCurrentOption().text)
  1248. if id == MarketCategory.MetaWeapons then
  1249. id = getMarketCategoryId(subCategoryList:getCurrentOption().text)
  1250. end
  1251. Market.loadMarketItems(id)
  1252. end
  1253.  
  1254. function Market.resetCreateOffer(resetFee)
  1255. piecePriceEdit:setValue(1)
  1256. totalPriceEdit:setValue(1)
  1257. amountEdit:setValue(1)
  1258. refreshTypeList()
  1259.  
  1260. if resetFee then
  1261. clearFee()
  1262. else
  1263. updateFee(0, 0)
  1264. end
  1265. end
  1266.  
  1267. -- Modify refreshItemsWidget for correct display
  1268. function Market.refreshItemsWidget(selectItem)
  1269. local selectItem = selectItem or 0
  1270. itemsPanel = browsePanel:recursiveGetChildById('itemsPanel')
  1271.  
  1272. local layout = itemsPanel:getLayout()
  1273. layout:disableUpdates()
  1274.  
  1275. Market.clearSelectedItem()
  1276. itemsPanel:destroyChildren()
  1277.  
  1278. if radioItemSet then
  1279. radioItemSet:destroy()
  1280. end
  1281. radioItemSet = UIRadioGroup.create()
  1282.  
  1283. local selectWidget = nil
  1284.  
  1285. for i = 1, #currentItems do
  1286. local item = currentItems[i]
  1287. local serverId = item.marketData.tradeAs -- Keep server ID for operations
  1288. local clientId = getClientId(serverId) -- Get client ID for display
  1289.  
  1290. local itemBox = g_ui.createWidget('MarketItemBox', itemsPanel)
  1291. itemBox.onCheckChange = Market.onItemBoxChecked
  1292. itemBox.item = item
  1293.  
  1294. if selectItem > 0 and serverId == selectItem then
  1295. selectWidget = itemBox
  1296. selectItem = 0
  1297. end
  1298.  
  1299. local itemWidget = itemBox:getChildById('item')
  1300. local displayItem = Item.create(clientId) -- Create with client ID
  1301. itemWidget:setItem(displayItem)
  1302.  
  1303. g_logger.debug(string.format("Setting market display - Server ID: %d, Client ID: %d",
  1304. serverId, clientId))
  1305.  
  1306. local amount = Market.getDepotCount(serverId) -- Use server ID for depot check
  1307. if amount > 0 then
  1308. itemWidget:setText(comma_value(amount))
  1309. itemBox:setTooltip('You have '.. amount ..' in your depot.')
  1310. end
  1311.  
  1312. radioItemSet:addWidget(itemBox)
  1313. end
  1314.  
  1315. if selectWidget then
  1316. radioItemSet:selectWidget(selectWidget, false)
  1317. end
  1318.  
  1319. layout:enableUpdates()
  1320. layout:update()
  1321. end
  1322.  
  1323. function Market.refreshOffers()
  1324. if Market.isItemSelected() then
  1325. Market.onItemBoxChecked(selectedItem.ref)
  1326. else
  1327. local ctab = offersTabBar:getCurrentTab()
  1328. if ctab == myCurrentOffersTab then
  1329. Market.refreshMyOffers()
  1330. elseif ctab == myOfferHistoryTab then
  1331. Market.refreshMyOffersHistory()
  1332. end
  1333. end
  1334. end
  1335.  
  1336. function Market.refreshMyOffers()
  1337. clearMyOffers()
  1338. MarketProtocol.sendMarketBrowseMyOffers()
  1339. end
  1340.  
  1341. function Market.refreshMyOffersHistory()
  1342. clearMyOffers()
  1343. MarketProtocol.sendMarketBrowseMyHistory()
  1344. end
  1345.  
  1346.  
  1347. function Market.loadMarketItems(category)
  1348. clearItems()
  1349.  
  1350. -- check search filter
  1351. local searchFilter = searchEdit:getText()
  1352. if searchFilter and searchFilter:len() > 2 then
  1353. if filterButtons[MarketFilters.SearchAll]:isChecked() then
  1354. category = MarketCategory.All
  1355. end
  1356. end
  1357.  
  1358. if not marketItems[category] and category ~= MarketCategory.All then
  1359. return
  1360. end
  1361.  
  1362. if category == MarketCategory.All then
  1363. -- loop all categories
  1364. for category = MarketCategory.First, MarketCategory.Last do
  1365. if marketItems[category] then
  1366. for i = 1, #marketItems[category] do
  1367. local item = marketItems[category][i]
  1368. if isItemValid(item, category, searchFilter) then
  1369. table.insert(currentItems, item)
  1370. end
  1371. end
  1372. end
  1373. end
  1374. else
  1375. -- loop specific category
  1376. for i = 1, #marketItems[category] do
  1377. local item = marketItems[category][i]
  1378. if isItemValid(item, category, searchFilter) then
  1379. table.insert(currentItems, item)
  1380. end
  1381. end
  1382. end
  1383.  
  1384. Market.refreshItemsWidget()
  1385. end
  1386.  
  1387. function Market.createNewOffer()
  1388. local type = offerTypeList:getCurrentOption().text
  1389. if type == 'Sell' then
  1390. type = MarketAction.Sell
  1391. else
  1392. type = MarketAction.Buy
  1393. end
  1394.  
  1395. if not Market.isItemSelected() then
  1396. return
  1397. end
  1398.  
  1399. local spriteId = selectedItem.item.marketData.tradeAs
  1400.  
  1401. local piecePrice = piecePriceEdit:getValue()
  1402. local amount = amountEdit:getValue()
  1403. local anonymous = anonymous:isChecked() and 1 or 0
  1404.  
  1405. -- error checking
  1406. local errorMsg = ''
  1407. if type == MarketAction.Buy then
  1408. if information.balance < ((piecePrice * amount) + fee) then
  1409. errorMsg = errorMsg..'Not enough balance to create this offer.\n'
  1410. end
  1411. elseif type == MarketAction.Sell then
  1412. if information.balance < fee then
  1413. errorMsg = errorMsg..'Not enough balance to create this offer.\n'
  1414. end
  1415. if Market.getDepotCount(spriteId) < amount then
  1416. errorMsg = errorMsg..'Not enough items in your depot to create this offer.\n'
  1417. end
  1418. end
  1419.  
  1420. if piecePrice > piecePriceEdit.maximum then
  1421. errorMsg = errorMsg..'Price is too high.\n'
  1422. elseif piecePrice < piecePriceEdit.minimum then
  1423. errorMsg = errorMsg..'Price is too low.\n'
  1424. end
  1425.  
  1426. if amount > amountEdit.maximum then
  1427. errorMsg = errorMsg..'Amount is too high.\n'
  1428. elseif amount < amountEdit.minimum then
  1429. errorMsg = errorMsg..'Amount is too low.\n'
  1430. end
  1431.  
  1432. if amount * piecePrice > MarketMaxPrice then
  1433. errorMsg = errorMsg..'Total price is too high.\n'
  1434. end
  1435.  
  1436. if information.totalOffers >= MarketMaxOffers then
  1437. errorMsg = errorMsg..'You cannot create more offers.\n'
  1438. end
  1439.  
  1440. local timeCheck = os.time() - lastCreatedOffer
  1441. if timeCheck < offerExhaust[type] then
  1442. local waitTime = math.ceil(offerExhaust[type] - timeCheck)
  1443. errorMsg = errorMsg..'You must wait '.. waitTime ..' seconds before creating a new offer.\n'
  1444. end
  1445.  
  1446. if errorMsg ~= '' then
  1447. Market.displayMessage(errorMsg)
  1448. return
  1449. end
  1450.  
  1451. MarketProtocol.sendMarketCreateOffer(type, spriteId, amount, piecePrice, anonymous)
  1452. lastCreatedOffer = os.time()
  1453. Market.resetCreateOffer()
  1454. end
  1455.  
  1456. function Market.acceptMarketOffer(amount, timestamp, counter)
  1457. if timestamp > 0 and amount > 0 then
  1458. MarketProtocol.sendMarketAcceptOffer(timestamp, counter, amount)
  1459. Market.refreshOffers()
  1460. end
  1461. end
  1462.  
  1463. function Market.onItemBoxChecked(widget)
  1464. if widget:isChecked() then
  1465. updateSelectedItem(widget)
  1466. end
  1467. end
  1468.  
  1469. -- protocol callback functions
  1470.  
  1471. function Market.onMarketEnter(depotItems, offers, balance, vocation, items)
  1472. if not loaded or (items and #items > 0) then
  1473. initMarketItems(items)
  1474. loaded = true
  1475. end
  1476.  
  1477. updateBalance(balance)
  1478. averagePrice = 0
  1479.  
  1480. information.totalOffers = offers
  1481. local player = g_game.getLocalPlayer()
  1482. if player then
  1483. information.player = player
  1484. end
  1485. if vocation == -1 then
  1486. if player then
  1487. information.vocation = player:getVocation()
  1488. end
  1489. else
  1490. -- vocation must be compatible with < 950
  1491. information.vocation = vocation
  1492. end
  1493.  
  1494. -- set list of depot items
  1495. information.depotItems = depotItems
  1496.  
  1497. for i = 1, #marketItems[MarketCategory.TibiaCoins] do
  1498. local item = marketItems[MarketCategory.TibiaCoins][i].displayItem
  1499. depotItems[item:getId()] = tibiaCoins
  1500. end
  1501.  
  1502. -- update the items widget to match depot items
  1503. if Market.isItemSelected() then
  1504. local spriteId = selectedItem.item.marketData.tradeAs
  1505. MarketProtocol.silent(true) -- disable protocol messages
  1506. Market.refreshItemsWidget(spriteId)
  1507. MarketProtocol.silent(false) -- enable protocol messages
  1508. else
  1509. Market.refreshItemsWidget()
  1510. end
  1511.  
  1512. if table.empty(currentItems) then
  1513. Market.loadMarketItems(MarketCategory.First)
  1514. end
  1515.  
  1516. if g_game.isOnline() then
  1517. marketWindow:lock()
  1518. marketWindow:show()
  1519. end
  1520. end
  1521.  
  1522. function Market.onMarketLeave()
  1523. Market.close(false)
  1524. end
  1525.  
  1526. function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats)
  1527. updateDetails(itemId, descriptions, purchaseStats, saleStats)
  1528. end
  1529.  
  1530. function Market.onMarketBrowse(offers, offersType)
  1531. if offersType == MarketRequest.MyHistory then
  1532. updateHistoryOffers(offers)
  1533. else
  1534. updateOffers(offers)
  1535. end
  1536. end
  1537.  
  1538. function Market.onCoinBalance(coins, transferableCoins)
  1539. tibiaCoins = coins
  1540. if not marketItems[MarketCategory.TibiaCoins] then return end
  1541. for i = 1, #marketItems[MarketCategory.TibiaCoins] do
  1542. local item = marketItems[MarketCategory.TibiaCoins][i].displayItem
  1543. information.depotItems[item:getId()] = tibiaCoins
  1544. end
  1545. end
  1546.  
Add Comment
Please, Sign In to add comment