diff --git a/modules/client_modulemanager/modulemanager.lua b/modules/client_modulemanager/modulemanager.lua index 3deb4098..4fab7c63 100644 --- a/modules/client_modulemanager/modulemanager.lua +++ b/modules/client_modulemanager/modulemanager.lua @@ -146,7 +146,7 @@ function ModuleManager.unloadCurrentModule() end function ModuleManager.reloadAllModules() - g_modules.g_modules.reloadModules() + g_modules.reloadModules() ModuleManager.refreshLoadedModules() ModuleManager.show() end diff --git a/modules/client_options/options.lua b/modules/client_options/options.lua index ebbd115a..9283c0e1 100644 --- a/modules/client_options/options.lua +++ b/modules/client_options/options.lua @@ -74,6 +74,7 @@ function Options.init() optionsWindow = g_ui.displayUI('options.otui') optionsWindow:hide() optionsButton = TopMenu.addLeftButton('optionsButton', tr('Options') .. ' (Ctrl+D)', 'options.png', Options.toggle) + optionsTabBar = optionsWindow:getChildById('optionsTabBar') optionsTabBar:setContentWidget(optionsWindow:getChildById('optionsTabContent')) diff --git a/modules/client_skins/skins/default/images/panel_lightflat.png b/modules/client_skins/skins/default/images/panel_lightflat.png new file mode 100644 index 00000000..b98810ab Binary files /dev/null and b/modules/client_skins/skins/default/images/panel_lightflat.png differ diff --git a/modules/client_skins/skins/default/styles/panels.otui b/modules/client_skins/skins/default/styles/panels.otui index 3e98bc79..41194265 100644 --- a/modules/client_skins/skins/default/styles/panels.otui +++ b/modules/client_skins/skins/default/styles/panels.otui @@ -15,3 +15,7 @@ ScrollableFlatPanel < ScrollablePanel ParticlesFlatPanel < Panel image-source: /images/panel_flat.png image-border: 1 + +LightFlatPanel < Panel + image-source: /images/panel_lightflat.png + image-border: 1 diff --git a/modules/corelib/table.lua b/modules/corelib/table.lua index aea858c7..3e8adaca 100644 --- a/modules/corelib/table.lua +++ b/modules/corelib/table.lua @@ -41,6 +41,18 @@ function table.find(t, value) end end +function table.findKey(t, key) + if t and type(t) == 'table' then + for k,v in pairs(t) do + if k == key then return k end + end + end +end + +function table.hasKey(t, key) + return table.findKey(t, key) ~= nil +end + function table.removevalue(t, value) for k,v in pairs(t) do if v == value then @@ -59,7 +71,7 @@ function table.compare(t, other) end function table.empty(t) - if(t) then + if t and type(t) == 'table' then return next(t) == nil end return true diff --git a/modules/game_interface/styles/exitwindow.otui b/modules/game_interface/styles/exitwindow.otui index f47ece50..78c85cd4 100644 --- a/modules/game_interface/styles/exitwindow.otui +++ b/modules/game_interface/styles/exitwindow.otui @@ -5,8 +5,8 @@ ExitWindow < MainWindow Label !text: tr('If you shut down the program, you character might stay in the game.\nClick on "Logout" to ensure that you character leaves the game property.\nClick on "Exit" if you want to exit the program without logging out your character.') - width: 550 - height: 110 + width: 500 + height: 45 anchors.left: parent.left anchors.top: parent.top margin-left: 10 diff --git a/modules/game_interface/styles/logoutwindow.otui b/modules/game_interface/styles/logoutwindow.otui index 985ddb98..559d3623 100644 --- a/modules/game_interface/styles/logoutwindow.otui +++ b/modules/game_interface/styles/logoutwindow.otui @@ -5,7 +5,7 @@ LogoutWindow < MainWindow Label !text: tr('Are you sure you want to logout?') - width: 300 + width: 200 anchors.left: parent.left anchors.top: parent.top margin-left: 30 diff --git a/modules/game_market/market.lua b/modules/game_market/market.lua index 891ac39b..841dedb7 100644 --- a/modules/game_market/market.lua +++ b/modules/game_market/market.lua @@ -1,61 +1,262 @@ Market = {} +g_ui.importStyle('market.otui') +g_ui.importStyle('ui/general/markettabs.otui') +g_ui.importStyle('ui/general/marketbuttons.otui') + local marketWindow +local mainTabBar + +local marketOffersPanel +local selectionTabBar +local browsePanel +local searchPanel + +local displaysTabBar +local itemOffersPanel +local itemDetailsPanel +local itemStatsPanel + +local myOffersPanel +local offersTabBar +local currentOffersPanel +local offerHistoryPanel + +local marketOffers = {} +local depot = {} +local information ={} +local selectedItem +local nameLabel + +local itemsPanel +local radioItems + +local function clearSelectedItem() + if selectedItem then + nameLabel:clearText() + radioItems:selectWidget(nil) + selectedItem.setItem(nil) + end +end + +local function loadMarketItems() + itemsPanel = marketWindow:recursiveGetChildById('itemsPanel') + + local layout = itemsPanel:getLayout() + layout:disableUpdates() + + clearSelectedItem() + itemsPanel:destroyChildren() + + if radioItemSet then + radioItemSet:destroy() + end + radioItemSet = UIRadioGroup.create() + + -- TODO: populate with dat items + + + layout:enableUpdates() + layout:update() +end + +local function loadDepotItems(depotItems) + information.depotItems = {} + for _, data in pairs(depotItems) do + local item = Item.create(data[1]) + if not item then + break + end + item:setCount(data[2]) + local marketData = item:getMarketData() + + if not table.empty(marketData) then + local newItem = { + ptr = item, + marketData = marketData + } + table.insert(information.depotItems, newItem) + end + end +end function Market.init() - g_ui.importStyle('market.otui') + marketWindow = g_ui.createWidget('MarketWindow', rootWidget) + marketWindow:hide() + + nameLabel = marketWindow:recursiveGetChildById('nameLabel') + + -- TODO: clean this up into functions + -- setup main tabs + mainTabBar = marketWindow:getChildById('mainTabBar') + mainTabBar:setContentWidget(marketWindow:getChildById('mainTabContent')) + + -- setup 'Market Offer' section tabs + marketOffersPanel = g_ui.loadUI('ui/marketoffers.otui') + mainTabBar:addTab(tr('Market Offers'), marketOffersPanel) + + selectionTabBar = marketOffersPanel:getChildById('leftTabBar') + selectionTabBar:setContentWidget(marketOffersPanel:getChildById('leftTabContent')) + + browsePanel = g_ui.loadUI('ui/marketoffers/browse.otui') + selectionTabBar:addTab(tr('Browse'), browsePanel) + + searchPanel = g_ui.loadUI('ui/marketoffers/search.otui') + selectionTabBar:addTab(tr('Search'), searchPanel) + displaysTabBar = marketOffersPanel:getChildById('rightTabBar') + displaysTabBar:setContentWidget(marketOffersPanel:getChildById('rightTabContent')) + + itemOffersPanel = g_ui.loadUI('ui/marketoffers/itemoffers.otui') + displaysTabBar:addTab(tr('Offers'), itemOffersPanel) + + itemDetailsPanel = g_ui.loadUI('ui/marketoffers/itemdetails.otui') + displaysTabBar:addTab(tr('Details'), itemDetailsPanel) + + itemStatsPanel = g_ui.loadUI('ui/marketoffers/itemstats.otui') + displaysTabBar:addTab(tr('Statistics'), itemStatsPanel) + + -- setup 'My Offer' section tabs + myOffersPanel = g_ui.loadUI('ui/myoffers.otui') + mainTabBar:addTab(tr('My Offers'), myOffersPanel) + + offersTabBar = myOffersPanel:getChildById('offersTabBar') + offersTabBar:setContentWidget(myOffersPanel:getChildById('offersTabContent')) + + currentOffersPanel = g_ui.loadUI('ui/myoffers/currentoffers.otui') + offersTabBar:addTab(tr('Current Offers'), currentOffersPanel) + + offerHistoryPanel = g_ui.loadUI('ui/myoffers/offerhistory.otui') + offersTabBar:addTab(tr('Offer History'), offerHistoryPanel) end function Market.terminate() - marketWindow = nil + if marketWindow then + marketWindow:destroy() + marketWindow = nil + end + + mainTabBar = nil + marketOffersPanel = nil + selectionTabBar = nil + browsePanel = nil + searchPanel = nil + displaysTabBar = nil + itemOffersPanel = nil + itemDetailsPanel = nil + itemStatsPanel = nil + myOffersPanel = nil + offersTabBar = nil + currentOffersPanel = nil + offerHistoryPanel = nil + marketOffers = {} + depotItems = {} + information = {} + itemsPanel = nil + nameLabel = nil + radioItems = nil + selectedItem = nil + Market = nil end +function Market.updateOffers(offers) + for k, offer in pairs(offers) do + if offer and offer:getAction() == MarketAction.Buy then + table.insert(marketOffers[MarketAction.Buy], offer) + else + table.insert(marketOffers[MarketAction.Sell], offer) + end + end + + for _, offers in pairs(marketOffers) do + for _, offer in pairs(offers) do + print(' counter: '..offer:getCounter()..' | timestamp: '..offer:getTimeStamp()..' | item: '..offer:getItem():getId()..' | action: '..offer:getAction()..' | amount: '..offer:getAmount()..' | price: '..offer:getPrice()..' | player: '..offer:getPlayer()..' | state: '..offer:getState()) + end + end + -- TODO: refresh all widget windows +end + +function Market.updateDetails(itemId, descriptions, purchaseStats, saleStats) + -- TODO: refresh all widget windows + +end + +function Market.updateSelectedItem(newItem) + local itemDisplay = marketWindow:recursiveGetChildById('selectedItem') + local itemName = marketWindow:recursiveGetChildById('nameLabel') + selectedItem = newItem + if not table.empty(selectedItem) then + if selectedItem.ptr then + itemDisplay:setItem(selectedItem.ptr) + itemName:setText(tr(selectedItem.name)) + MarketProtocol.sendMarketBrowse(selectedItem.ptr:getId()) -- send sprite id browsed + end + else + itemDisplay:setItem(nil) + itemName:setText(tr('No item selected.')) + end +end + function Market.onMarketEnter(depotItems, offers, balance) - -- open market window - -- populate market? - print('onMarketEnter') - print(offers) - print(balance) - print('depotItems:') - for k, item in pairs(depotItems) do - print('id- '..item[1]) - print('count- '..item[2]) + -- TODO: populate market? + if marketWindow:isVisible() then + return end + marketOffers[MarketAction.Buy] = {} + marketOffers[MarketAction.Sell] = {} + + information.balance = balance + information.totalOffers = offers + + loadMarketItems() + loadDepotItems(depotItems) + + -- TODO: if you are already viewing an item on market enter it must recheck the current item + if selectedItem and selectedItem:isChecked() then + selectedItem:setChecked(false) + selectedItem:setChecked(true) + end + --MarketProtocol.sendMarketBrowse(645) + marketWindow:show() end function Market.onMarketLeave() - -- close market window? - print('onMarketLeave') + marketWindow:hide() end function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats) - -- populate market widget - print('onMarketDetail') - print(itemId) + Market.updateDetails(itemId, descriptions, purchaseStats, saleStats) + + print('') + print('[onMarketDetail]') + print('itemId: '..itemId) print('descriptions:') for k, desc in pairs(descriptions) do - print('type- '..desc[1]) - print('description- '..desc[2]) + print(' type: '..desc[1]..' | description: '..desc[2]) end print('purchaseStats:') for k, stat in pairs(purchaseStats) do - print('transactions- '..stat[1]) - print('total price- '..stat[2]) - print('highest price- '..stat[3]) - print('lowest price- '..stat[4]) + print(' transactions: '..stat[1]) + print(' total price: '..stat[2]) + print(' highest price: '..stat[3]) + print(' lowest price: '..stat[4]) end print('saleStats:') for k, stat in pairs(saleStats) do - print('transactions- '..stat[1]) - print('total price- '..stat[2]) - print('highest price- '..stat[3]) - print('lowest price- '..stat[4]) + print(' transactions: '..stat[1]) + print(' total price: '..stat[2]) + print(' highest price: '..stat[3]) + print(' lowest price: '..stat[4]) end end function Market.onMarketBrowse(offers) - -- populate market widget - print('onMarketBrowse') + Market.updateOffers(offers) end + +function Market.onItemBoxChecked(widget) + if widget:isChecked() then + Market.updateSelectedItem(widget.item) + end +end \ No newline at end of file diff --git a/modules/game_market/market.otui b/modules/game_market/market.otui index 6ed320b7..837b7e73 100644 --- a/modules/game_market/market.otui +++ b/modules/game_market/market.otui @@ -1,29 +1,26 @@ MarketWindow < MainWindow id: marketWindow !text: tr('Market') - size: 350 155 + size: 680 460 - Label - !text: tr('Alas! Brave adventurer, you have met a sad fate.\nBut do not despair, for the gods will bring you back\ninto this world in exchange for a small sacrifice\n\nSimply click on Ok to resume your journeys!') - width: 550 - height: 140 - anchors.left: parent.left - anchors.top: parent.top - margin-left: 10 - margin-top: 2 + @onEnter: self:hide() + @onEscape: self:hide() + + // Main Panel Window - Button - id: buttonOk - !text: tr('Ok') - width: 64 + MarketTabBar + id: mainTabBar + width: 164 + height: 25 + anchors.top: parent.top anchors.left: parent.left - anchors.bottom: parent.bottom - margin-left: 160 - Button - id: buttonCancel - !text: tr('Cancel') - width: 64 - anchors.left: prev.right + Panel + id: mainTabContent + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right anchors.bottom: parent.bottom - margin-left: 5 + padding: 3 + border-width: 1 + border-color: #000000 diff --git a/modules/game_market/marketoffer.lua b/modules/game_market/marketoffer.lua index 13bd16a9..34f55868 100644 --- a/modules/game_market/marketoffer.lua +++ b/modules/game_market/marketoffer.lua @@ -4,7 +4,7 @@ MarketOffer.__index = MarketOffer local OFFER_TIMESTAMP = 1 local OFFER_COUNTER = 2 -MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, state) +MarketOffer.new = function(offerId, action, item, amount, price, playerName, state) local offer = { id = {}, action = nil, @@ -26,7 +26,11 @@ MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, s end offer.action = action - offer.item = itemId + if not item then + g_logger.error('MarketOffer.new - invalid item provided.') + end + offer.item = item + offer.amount = amount offer.price = price offer.player = playerName @@ -67,8 +71,19 @@ 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.') + end + self.action = action +end + +function MarketOffer:getAction() + return self.action +end + function MarketOffer:setItem(item) - if not item or type(item) ~= 'number' then + if not item or type(item) ~= 'userdata' then g_logger.error('MarketOffer.setItem - invalid item id provided.') end self.item = item diff --git a/modules/game_market/marketprotocol.lua b/modules/game_market/marketprotocol.lua index 807d2fa2..7fe7baab 100644 --- a/modules/game_market/marketprotocol.lua +++ b/modules/game_market/marketprotocol.lua @@ -1,11 +1,15 @@ MarketProtocol = {} -local market - -- private functions + +local protocol + local function send(msg) - print(msg:getMessageSize()) - g_game.getProtocolGame():safeSend(msg) + if protocol then + print(msg:getMessageSize()) + --protocol:safeSend(msg) + protocol:send(msg) + end end local function readMarketOffer(msg, action, var) @@ -29,12 +33,15 @@ local function readMarketOffer(msg, action, var) playerName = msg:getString() end - return MarketOffer.new({timestamp, counter}, action, itemId, amount, price, playerName, state) + return MarketOffer.new({timestamp, counter}, action, Item.create(itemId), amount, price, playerName, state) end -- parsing protocols local function parseMarketEnter(msg) local balance = msg:getU32() + if g_game.getProtocolVersion() < 950 then + msg:getU8() -- get vocation id + end local offers = msg:getU8() local depotItems = {} @@ -47,10 +54,12 @@ local function parseMarketEnter(msg) end Market.onMarketEnter(depotItems, offers, balance) + return true end local function parseMarketLeave(msg) Market.onMarketLeave() + return true end local function parseMarketDetail(msg) @@ -59,7 +68,7 @@ local function parseMarketDetail(msg) local descriptions = {} for i = MarketItemDescription.First, MarketItemDescription.Last do if msg:peekU16() ~= 0x00 then - table.insert(descriptions, {i, msg:getString()}) + table.insert(descriptions, {i, msg:getString()}) -- item descriptions else msg:getU16() end @@ -86,6 +95,7 @@ local function parseMarketDetail(msg) end Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats) + return true end local function parseMarketBrowse(msg) @@ -103,26 +113,55 @@ local function parseMarketBrowse(msg) end Market.onMarketBrowse(offers) + return true end -- public functions function MarketProtocol.init() - ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter) - ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave) - ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail) - ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse) + connect(g_game, { onGameStart = MarketProtocol.registerProtocol, + onGameEnd = MarketProtocol.unregisterProtocol }) + + -- reloading module + if g_game.isOnline() then + MarketProtocol.updateProtocol(g_game.getProtocolGame()) + end end function MarketProtocol.terminate() - ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter) - ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave) - ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail) - ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse) + disconnect(g_game, { onGameStart = MarketProtocol.registerProtocol, + onGameEnd = MarketProtocol.unregisterProtocol }) - market = nil + -- reloading module + if not g_game.isOnline() then + MarketProtocol.updateProtocol(nil) + end MarketProtocol = nil end +function MarketProtocol.updateProtocol(_protocol) + protocol = _protocol +end + +function MarketProtocol.registerProtocol() + if g_game.getFeature(GamePlayerMarket) then + ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter) + ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave) + ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail) + ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse) + end + MarketProtocol.updateProtocol(g_game.getProtocolGame()) +end + +function MarketProtocol.unregisterProtocol() + if g_game.getFeature(GamePlayerMarket) then + ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter) + ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave) + ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail) + ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse) + end + MarketProtocol.updateProtocol(nil) +end + -- sending protocols function MarketProtocol.sendMarketLeave() diff --git a/modules/game_market/ui/general/marketbuttons.otui b/modules/game_market/ui/general/marketbuttons.otui new file mode 100644 index 00000000..5a737563 --- /dev/null +++ b/modules/game_market/ui/general/marketbuttons.otui @@ -0,0 +1,20 @@ +MarketButtonBox < UICheckBox + font: verdana-11px-antialised + color: #ffffffff + size: 106 22 + text-offset: 0 0 + text-align: center + image-source: /images/tabbutton.png + image-clip: 0 0 20 20 + image-border: 2 + + $hover !disabled: + image-clip: 0 20 20 20 + + $checked: + image-clip: 0 40 20 20 + color: white + + $disabled: + color: #666666ff + image-color: #ffffff88 diff --git a/modules/game_market/ui/general/markettabs.otui b/modules/game_market/ui/general/markettabs.otui new file mode 100644 index 00000000..8e1ffd1c --- /dev/null +++ b/modules/game_market/ui/general/markettabs.otui @@ -0,0 +1,33 @@ +MarketTabBar < UITabBar + size: 80 20 +MarketTabBarPanel < Panel +MarketTabBarButton < UIButton + size: 20 25 + image-source: /images/tabbutton.png + image-clip: 0 0 20 20 + image-border: 2 + icon-color: white + color: #aaaaaa + anchors.top: parent.top + padding: 5 + + $first: + anchors.left: parent.left + + $!first: + anchors.left: prev.right + + $hover !checked: + image-clip: 0 20 20 20 + color: white + + $disabled: + image-color: #ffffff66 + icon-color: #888888 + + $checked: + image-clip: 0 20 20 20 + color: #ffffff + + $on !checked: + color: #f55e5e diff --git a/modules/game_market/ui/marketoffers.otui b/modules/game_market/ui/marketoffers.otui new file mode 100644 index 00000000..62b9d234 --- /dev/null +++ b/modules/game_market/ui/marketoffers.otui @@ -0,0 +1,49 @@ +Panel + + MarketTabBar + id: leftTabBar + width: 107 + height:25 + anchors.top: parent.top + anchors.left: parent.left + + Panel + id: leftTabContent + width: 180 + anchors.top: prev.bottom + anchors.left: prev.left + anchors.bottom: parent.bottom + border-width: 1 + border-color: #000000 + + MarketTabBar + id: rightTabBar + width: 157 + height:25 + anchors.top: parent.top + anchors.right: parent.right + + Panel + id: rightTabContent + anchors.top: prev.bottom + anchors.left: leftTabContent.right + anchors.right: prev.right + anchors.bottom: parent.bottom + margin-left:3 + border-width: 1 + border-color: #000000 + + Item + id: selectedItem + phantom: true + anchors.top: rightTabBar.bottom + anchors.left: rightTabContent.left + margin-top: 3 + margin-left: 3 + + Label + id: nameLabel + !text: tr('No item selected.') + anchors.top: prev.top + anchors.left: prev.right + margin-left: 5 diff --git a/modules/game_market/ui/marketoffers/browse.otui b/modules/game_market/ui/marketoffers/browse.otui new file mode 100644 index 00000000..c8641ab8 --- /dev/null +++ b/modules/game_market/ui/marketoffers/browse.otui @@ -0,0 +1,125 @@ +MarketItemBox < UICheckBox + border-width: 1 + border-color: #000000 + color: #aaaaaa + text-align: center + text-offset: 0 20 + @onCheckChange: Market.onItemBoxChecked(self) + + Item + id: item + phantom: true + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + margin-top: 5 + + $checked: + border-color: #ffffff + + $hover !checked: + border-color: #aaaaaa + + $disabled: + image-color: #ffffff88 + color: #aaaaaa88 + +Panel + background-color: #22283399 + margin: 1 + + ComboBox + id: filterComboBox + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + margin-top: 3 + margin-right: 3 + margin-left: 3 + + ComboBox + id: weaponComboBox + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 3 + margin-right: 3 + margin-left: 3 + + MarketButtonBox + id: filterMatchLevel + checked: false + !text: tr('Level') + !tooltip: tr('Filter list to match your level') + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 3 + margin-right: 3 + margin-left: 3 + width: 40 + height: 20 + //@onClick: Market.filterMatchLevel() + + MarketButtonBox + id: filterMatchVocation + checked: false + !text: tr('Vocation') + !tooltip: tr('Filter list to match your vocation') + anchors.top: prev.top + anchors.left: prev.right + margin-right: 3 + margin-left: 3 + width: 60 + height: 20 + //@onClick: Market.filterMatchVocation() + + ComboBox + id: typeComboBox + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-right: 3 + margin-left: 3 + + MarketButtonBox + id: showDepotOnly + checked: false + !text: tr('Show Depot Only') + !tooltip: tr('Show your depot items only') + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 3 + margin-right: 3 + margin-left: 3 + //@onClick: Market.setDisplayDepot() + + Panel + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + margin-top: 10 + margin-left: 3 + margin-bottom: 10 + margin-right: 3 + + VerticalScrollBar + id: itemsPanelListScrollBar + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + step: 16 + pixels-scroll: true + + ScrollablePanel + id: itemsPanel + anchors.left: parent.left + anchors.right: prev.left + anchors.top: parent.top + anchors.bottom: parent.bottom + vertical-scrollbar: itemsPanelListScrollBar + layout: + type: grid + cell-size: 34 34 + flow: true + auto-spacing: true \ No newline at end of file diff --git a/modules/game_market/ui/marketoffers/itemdetails.otui b/modules/game_market/ui/marketoffers/itemdetails.otui new file mode 100644 index 00000000..0916dda6 --- /dev/null +++ b/modules/game_market/ui/marketoffers/itemdetails.otui @@ -0,0 +1,10 @@ +Panel + background-color: #22283399 + margin: 1 + + Label + !text: tr('Item Details') + anchors.top: parent.top + anchors.left: parent.left + margin-top: 45 + margin-left: 3 diff --git a/modules/game_market/ui/marketoffers/itemoffers.otui b/modules/game_market/ui/marketoffers/itemoffers.otui new file mode 100644 index 00000000..8c105075 --- /dev/null +++ b/modules/game_market/ui/marketoffers/itemoffers.otui @@ -0,0 +1,10 @@ +Panel + background-color: #22283399 + margin: 1 + + Label + !text: tr('Item Offers') + anchors.top: parent.top + anchors.left: parent.left + margin-top: 45 + margin-left: 3 \ No newline at end of file diff --git a/modules/game_market/ui/marketoffers/itemstats.otui b/modules/game_market/ui/marketoffers/itemstats.otui new file mode 100644 index 00000000..44a7280b --- /dev/null +++ b/modules/game_market/ui/marketoffers/itemstats.otui @@ -0,0 +1,10 @@ +Panel + background-color: #22283399 + margin: 1 + + Label + !text: tr('Item Stats') + anchors.top: parent.top + anchors.left: parent.left + margin-top: 45 + margin-left: 3 diff --git a/modules/game_market/ui/marketoffers/search.otui b/modules/game_market/ui/marketoffers/search.otui new file mode 100644 index 00000000..8b2ffa37 --- /dev/null +++ b/modules/game_market/ui/marketoffers/search.otui @@ -0,0 +1,9 @@ +Panel + background-color: #22283399 + margin: 1 + + Label + !text: tr('Search') + anchors.top: parent.top + anchors.left: parent.left + margin-left: 10 diff --git a/modules/game_market/ui/myoffers.otui b/modules/game_market/ui/myoffers.otui new file mode 100644 index 00000000..cfa39d0a --- /dev/null +++ b/modules/game_market/ui/myoffers.otui @@ -0,0 +1,16 @@ +Panel + + MarketTabBar + id: offersTabBar + width: 187 + height:25 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + Panel + id: offersTabContent + anchors.top: prev.bottom + anchors.left: prev.left + anchors.right: prev.right + anchors.bottom: parent.bottom diff --git a/modules/game_market/ui/myoffers/currentoffers.otui b/modules/game_market/ui/myoffers/currentoffers.otui new file mode 100644 index 00000000..97c983f8 --- /dev/null +++ b/modules/game_market/ui/myoffers/currentoffers.otui @@ -0,0 +1,9 @@ +Panel + background-color: #22283399 + margin: 1 + + Label + !text: tr('Current Offers') + anchors.top: parent.top + anchors.left: parent.left + margin-left: 10 diff --git a/modules/game_market/ui/myoffers/itemoffers.otui b/modules/game_market/ui/myoffers/itemoffers.otui new file mode 100644 index 00000000..c649ce8f --- /dev/null +++ b/modules/game_market/ui/myoffers/itemoffers.otui @@ -0,0 +1,9 @@ +Panel + background-color: #22283399 + margin: 1 + + Label + !text: tr('Item Offers') + anchors.top: parent.top + anchors.left: parent.left + margin-left: 10 diff --git a/modules/game_market/ui/myoffers/offerhistory.otui b/modules/game_market/ui/myoffers/offerhistory.otui new file mode 100644 index 00000000..d9c9fa3d --- /dev/null +++ b/modules/game_market/ui/myoffers/offerhistory.otui @@ -0,0 +1,9 @@ +Panel + background-color: #22283399 + margin: 1 + + Label + !text: tr('Offer History') + anchors.top: parent.top + anchors.left: parent.left + margin-left: 10 diff --git a/modules/game_outfit/outfit.lua b/modules/game_outfit/outfit.lua index b29ffadf..02273045 100644 --- a/modules/game_outfit/outfit.lua +++ b/modules/game_outfit/outfit.lua @@ -150,14 +150,35 @@ function Outfit.create(creatureOutfit, outfitList, creatureMount, mountList) mountCreature = creatureMount outfits = outfitList mounts = mountList - Outfit.destroy() + Outfit.destroy() outfitWindow = g_ui.displayUI('outfitwindow.otui') - outfit = outfitCreature:getOutfit() - if mountCreature then + local colorBoxPanel = outfitWindow:getChildById('colorBoxPanel') + + -- setup outfit/mount display boxs + local outfitCreatureBox = outfitWindow:getChildById('outfitCreatureBox') + if outfitCreature then + outfit = outfitCreature:getOutfit() + outfitCreatureBox:setCreature(outfitCreature) + else + outfitCreatureBox:hide() + outfitWindow:getChildById('outfitName'):hide() + outfitWindow:getChildById('outfitNextButton'):hide() + outfitWindow:getChildById('outfitPrevButton'):hide() + end + + local mountCreatureBox = outfitWindow:getChildById('mountCreatureBox') + if mountCreature then mount = mountCreature:getOutfit() + mountCreatureBox:setCreature(mountCreature) + else + mountCreatureBox:hide() + outfitWindow:getChildById('mountName'):hide() + outfitWindow:getChildById('mountNextButton'):hide() + outfitWindow:getChildById('mountPrevButton'):hide() end + -- set addons addons = { [1] = {widget = outfitWindow:getChildById('addon1'), value = 1}, [2] = {widget = outfitWindow:getChildById('addon2'), value = 2}, @@ -174,21 +195,14 @@ function Outfit.create(creatureOutfit, outfitList, creatureMount, mountList) end end + -- hook outfit sections currentClotheButtonBox = outfitWindow:getChildById('head') outfitWindow:getChildById('head').onCheckChange = onClotheCheckChange outfitWindow:getChildById('primary').onCheckChange = onClotheCheckChange outfitWindow:getChildById('secondary').onCheckChange = onClotheCheckChange outfitWindow:getChildById('detail').onCheckChange = onClotheCheckChange - local outfitCreatureBox = outfitWindow:getChildById('outfitCreatureBox') - local colorBoxPanel = outfitWindow:getChildById('colorBoxPanel') - outfitCreatureBox:setCreature(outfitCreature) - - if mountCreature then - local mountCreatureBox = outfitWindow:getChildById('mountCreatureBox') - mountCreatureBox:setCreature(mountCreature) - end - + -- populate color panel for j=0,6 do for i=0,18 do local colorBox = g_ui.createWidget('ColorBox', colorBoxPanel) @@ -206,9 +220,10 @@ function Outfit.create(creatureOutfit, outfitList, creatureMount, mountList) end end + -- set current outfit/mount currentOutfit = 1 for i=1,#outfitList do - if outfitList[i][1] == outfit.type then + if outfit and outfitList[i][1] == outfit.type then currentOutfit = i break end diff --git a/modules/game_outfit/outfitwindow.otui b/modules/game_outfit/outfitwindow.otui index 09b9bea6..4e3f44ec 100644 --- a/modules/game_outfit/outfitwindow.otui +++ b/modules/game_outfit/outfitwindow.otui @@ -48,7 +48,7 @@ Window Label id: outfitName !text: tr('No Outfit') - width: 100 + width: 115 anchors.bottom: prev.top anchors.left: prev.left margin-bottom: 2 @@ -81,7 +81,7 @@ Window Label id: mountName !text: tr('No Mount') - width: 140 + width: 115 anchors.bottom: prev.top anchors.left: prev.left margin-bottom: 2 @@ -95,7 +95,7 @@ Window @onClick: Outfit.nextMountType() PrevMountButton - id: mountPreviousButton + id: mountPrevButton anchors.right: mountCreatureBox.left anchors.verticalCenter: mountCreatureBox.verticalCenter margin-right: 3 @@ -170,7 +170,7 @@ Window anchors.left: head.left margin-top: 3 margin-right: 20 - width: 323 + width: 302 height: 119 layout: type: grid diff --git a/modules/game_playermount/playermount.lua b/modules/game_playermount/playermount.lua index 61556355..2479d94d 100644 --- a/modules/game_playermount/playermount.lua +++ b/modules/game_playermount/playermount.lua @@ -1,11 +1,15 @@ PlayerMount = {} function PlayerMount.init() - g_keyboard.bindKeyDown('Ctrl+R', PlayerMount.toggleMount, gameRootPanel) + if g_game.getFeature(GamePlayerMount) then + g_keyboard.bindKeyDown('Ctrl+R', PlayerMount.toggleMount, gameRootPanel) + end end function PlayerMount.terminate() - g_keyboard.unbindKeyDown('Ctrl+R', gameRootPanel) + if g_game.getFeature(GamePlayerMount) then + g_keyboard.unbindKeyDown('Ctrl+R', gameRootPanel) + end PlayerMount = nil end diff --git a/modules/gamelib/market.lua b/modules/gamelib/market.lua index 7c8ebc2f..cc1d5e0f 100644 --- a/modules/gamelib/market.lua +++ b/modules/gamelib/market.lua @@ -31,8 +31,7 @@ MarketItemDescription = { Ability = 12, Charges = 13, WeaponName = 14, - Weight = 15, - - First = Armor, - Last = Weight + Weight = 15 } +MarketItemDescription.First = MarketItemDescription.Armor +MarketItemDescription.Last = MarketItemDescription.Weight diff --git a/src/otclient/game.cpp b/src/otclient/game.cpp index 484de093..a080b35b 100644 --- a/src/otclient/game.cpp +++ b/src/otclient/game.cpp @@ -1074,7 +1074,7 @@ bool Game::checkBotProtection() // accepts calls comming from a stacktrace containing only C++ functions, // if the stacktrace contains a lua function, then only accept if the engine is processing an input event if(m_denyBotCall && g_lua.isInCppCallback() && !g_app.isOnInputEvent()) { - g_logger.error(g_lua.traceback("caught a lua call to a bot protected game function, the call was canceled")); + g_logger.error(g_lua.traceback("caught a lua call to a bot protected game function, the call was cancelled")); return false; } #endif diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 7144cc79..a53697ab 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -274,7 +274,9 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("isHookSouth", &Thing::isHookSouth); g_lua.bindClassMemberFunction("isTranslucent", &Thing::isTranslucent); g_lua.bindClassMemberFunction("isFullGround", &Thing::isFullGround); + g_lua.bindClassMemberFunction("isMarketable", &Thing::isMarketable); g_lua.bindClassMemberFunction("getParentContainer", &Thing::getParentContainer); + g_lua.bindClassMemberFunction("getMarketData", &Thing::getMarketData); g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return HousePtr(new House); }); @@ -334,6 +336,8 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("getCount", &Item::getCount); g_lua.bindClassMemberFunction("getId", &Item::getId); g_lua.bindClassMemberFunction("isStackable", &Item::isStackable); + g_lua.bindClassMemberFunction("isMarketable", &Item::isMarketable); + g_lua.bindClassMemberFunction("getMarketData", &Item::isMarketable); g_lua.registerClass(); g_lua.registerClass(); diff --git a/src/otclient/luavaluecasts.cpp b/src/otclient/luavaluecasts.cpp index ef4052a7..16f91fb2 100644 --- a/src/otclient/luavaluecasts.cpp +++ b/src/otclient/luavaluecasts.cpp @@ -97,3 +97,41 @@ bool luavalue_cast(int index, Position& pos) } return false; } + +int push_luavalue(const MarketData& data) +{ + g_lua.newTable(); + g_lua.pushInteger(data.category); + g_lua.setField("category"); + g_lua.pushString(data.name); + g_lua.setField("name"); + g_lua.pushInteger(data.requiredLevel); + g_lua.setField("requiredLevel"); + g_lua.pushInteger(data.restrictProfession); + g_lua.setField("restrictProfession"); + g_lua.pushInteger(data.showAs); + g_lua.setField("showAs"); + g_lua.pushInteger(data.tradeAs); + g_lua.setField("tradeAs"); + return 1; +} + +bool luavalue_cast(int index, MarketData& data) +{ + if(g_lua.isTable(index)) { + g_lua.getField("category", index); + data.category = g_lua.popInteger(); + g_lua.getField("name", index); + data.name = g_lua.popString(); + g_lua.getField("requiredLevel", index); + data.requiredLevel = g_lua.popInteger(); + g_lua.getField("restrictProfession", index); + data.restrictProfession = g_lua.popInteger(); + g_lua.getField("showAs", index); + data.showAs = g_lua.popInteger(); + g_lua.getField("tradeAs", index); + data.tradeAs = g_lua.popInteger(); + return true; + } + return false; +} diff --git a/src/otclient/luavaluecasts.h b/src/otclient/luavaluecasts.h index fc9fce66..38b4b01d 100644 --- a/src/otclient/luavaluecasts.h +++ b/src/otclient/luavaluecasts.h @@ -36,4 +36,8 @@ bool luavalue_cast(int index, Outfit& outfit); int push_luavalue(const Position& pos); bool luavalue_cast(int index, Position& pos); +// market +int push_luavalue(const MarketData& data); +bool luavalue_cast(int index, MarketData& data); + #endif diff --git a/src/otclient/thing.h b/src/otclient/thing.h index 4fb1dcc7..4fbe369a 100644 --- a/src/otclient/thing.h +++ b/src/otclient/thing.h @@ -128,8 +128,10 @@ public: bool isFullGround() { return rawGetDatType()->isFullGround(); } bool isIgnoreLook() { return rawGetDatType()->isIgnoreLook(); } bool isCloth() { return rawGetDatType()->isCloth(); } + bool isMarketable() { return rawGetDatType()->isMarketable(); } MarketData getMarketData() { return rawGetDatType()->getMarketData(); } + protected: Position m_position; uint16 m_datId; diff --git a/src/otclient/thingtypedat.h b/src/otclient/thingtypedat.h index 6ea268a9..c308a5fd 100644 --- a/src/otclient/thingtypedat.h +++ b/src/otclient/thingtypedat.h @@ -172,6 +172,7 @@ public: bool isFullGround() { return m_attribs.has(DatAttribFullGround); } bool isIgnoreLook() { return m_attribs.has(DatAttribIgnoreLook); } bool isCloth() { return m_attribs.has(DatAttribCloth); } + bool isMarketable() { return m_attribs.has(DatAttribMarket); } private: const TexturePtr& getTexture(int animationPhase); diff --git a/src/otclient/thingtypemanager.h b/src/otclient/thingtypemanager.h index b0879661..a9f72626 100644 --- a/src/otclient/thingtypemanager.h +++ b/src/otclient/thingtypemanager.h @@ -48,8 +48,8 @@ public: const ThingTypeDatPtr& getDatType(uint16 id, DatCategory category); const ThingTypeOtbPtr& getOtbType(uint16 id); - ThingTypeDat *rawGetDatType(uint16 id, DatCategory category) { return m_datTypes[category][id].get(); } - ThingTypeOtb *rawGetOtbType(uint16 id) { return m_otbTypes[id].get(); } + ThingTypeDat* rawGetDatType(uint16 id, DatCategory category) { return m_datTypes[category][id].get(); } + ThingTypeOtb* rawGetOtbType(uint16 id) { return m_otbTypes[id].get(); } uint32 getDatSignature() { return m_datSignature; } uint32 getOtbMajorVersion() { return m_otbMajorVersion; }