diff --git a/modules/client_options/graphics.otui b/modules/client_options/graphics.otui index 53cddf2e..ec7bdf68 100644 --- a/modules/client_options/graphics.otui +++ b/modules/client_options/graphics.otui @@ -14,17 +14,17 @@ Panel anchors.top: parent.top ButtonBox + id: opengl1 anchors.left: prev.right anchors.verticalCenter: prev.verticalCenter - id: opengl1 text: OpenGL 1 size: 80 20 margin-left: 6 ButtonBox + id: opengl2 anchors.left: prev.right anchors.verticalCenter: prev.verticalCenter - id: opengl2 text: OpenGL 2 size: 80 20 margin-left: 4 diff --git a/modules/client_terminal/commands.lua b/modules/client_terminal/commands.lua index 4ba1172a..0a7ea20a 100644 --- a/modules/client_terminal/commands.lua +++ b/modules/client_terminal/commands.lua @@ -34,7 +34,20 @@ function debugContainersItems() function UIItem:onHoverChange(hovered) if hovered then local item = self:getItem() - if item then g_tooltip.display(item:getId()) end + if item then + local texts = { + 'id: '..item:getId(), + '\nstackable: '..tostring(item:isStackable()), + '\nmarketable: '..tostring(item:isMarketable()), + '\nvocation: '..(item:getMarketData() and item:getMarketData().restrictVocation or 'none'), + '\ncloth slot: '..item:getClothSlot() + } + local text = '' + for _, str in pairs(texts) do + text = text..str + end + g_tooltip.display(text) + end else g_tooltip.hide() end diff --git a/modules/corelib/bitwise.lua b/modules/corelib/bitwise.lua new file mode 100644 index 00000000..dcce309c --- /dev/null +++ b/modules/corelib/bitwise.lua @@ -0,0 +1,17 @@ +Bit = {} + +function Bit.bit(p) + return 2 ^ p +end + +function Bit.hasBit(x, p) + return x % (p + p) >= p +end + +function Bit.setbit(x, p) + return Bit.hasBit(x, p) and x or x + p +end + +function Bit.clearbit(x, p) + return Bit.hasBit(x, p) and x - p or x +end \ No newline at end of file diff --git a/modules/corelib/corelib.otmod b/modules/corelib/corelib.otmod index 6aa98eba..d48da48d 100644 --- a/modules/corelib/corelib.otmod +++ b/modules/corelib/corelib.otmod @@ -9,6 +9,7 @@ Module dofile 'math' dofile 'string' dofile 'table' + dofile 'bitwise' dofile 'const' dofile 'util' diff --git a/modules/corelib/ui/uicombobox.lua b/modules/corelib/ui/uicombobox.lua index c91ba3b2..1b957d4c 100644 --- a/modules/corelib/ui/uicombobox.lua +++ b/modules/corelib/ui/uicombobox.lua @@ -8,6 +8,12 @@ function UIComboBox.create() return combobox end +function UIComboBox:clearOptions() + self.options = {} + self.currentIndex = -1 + self:clearText() +end + function UIComboBox:setCurrentOption(text) if not self.options then return end for i,v in ipairs(self.options) do @@ -29,6 +35,12 @@ function UIComboBox:setCurrentIndex(index) end end +function UIComboBox:getCurrentOption() + if table.hasKey(self.options, self.currentIndex) then + return self.options[self.currentIndex] + end +end + function UIComboBox:addOption(text, data) table.insert(self.options, { text = text, data = data }) local index = #self.options diff --git a/modules/game_market/market.lua b/modules/game_market/market.lua index 4bc2186f..5c34f730 100644 --- a/modules/game_market/market.lua +++ b/modules/game_market/market.lua @@ -10,35 +10,38 @@ local mainTabBar local marketOffersPanel local selectionTabBar +local displaysTabBar +local offersTabBar + +local itemsPanel local browsePanel local searchPanel - -local displaysTabBar local itemOffersPanel local itemDetailsPanel local itemStatsPanel - local myOffersPanel -local offersTabBar local currentOffersPanel local offerHistoryPanel -local marketOffers = {} -local marketItems = {} -local depot = {} -local information ={} local selectedItem local nameLabel +local radioItemSet +local categoryList +local subCategoryList +local slotFilterList +local filterButtons = {} + local buyOfferTable local sellOfferTable local detailsTable local buyStatsTable local sellStatsTable +local marketOffers = {} +local marketItems = {} +local depot = {} +local information = {} local currentItems = {} -local itemsPanel -local radioItemSet -local filterBox local offerTableHeader = { {['text'] = 'Player Name', ['width'] = 100}, @@ -74,6 +77,56 @@ local function getMarketDescriptionId(name) end end +local function getMarketSlotFilterId(name) + local id = table.find(MarketSlotFilters, name) + if id then + return id + end +end + +local function getMarketSlotFilterName(id) + if table.hasKey(MarketSlotFilters, id) then + return MarketSlotFilters[id] + end +end + +local function isValidItem(item, category) + if item.marketData.category ~= category and category ~= MarketCategory[0] then + return false + end + + -- filter item + local slotFilter = false + if slotFilterList:isEnabled() then + slotFilter = getMarketSlotFilterId(slotFilterList:getCurrentOption().text) + end + local marketData = item.marketData + + local filterVocation = filterButtons[MarketFilters.Vocation]:isChecked() + local filterLevel = filterButtons[MarketFilters.Level]:isChecked() + local filterDepot = filterButtons[MarketFilters.Depot]:isChecked() + + if slotFilter then + if slotFilter ~= 255 and item.ptr:getClothSlot() ~= slotFilter then + return false + end + end + local player = g_game.getLocalPlayer() + if filterLevel and marketData.requiredLevel and player:getLevel() < marketData.requiredLevel then + return false + end + if filterVocation and marketData.restrictVocation > 0 then + local voc = Bit.bit(information.vocation) + if not Bit.hasBit(marketData.restrictVocation, voc) then + return false + end + end + if filterDepot and not Market.depotContains(item.ptr:getId()) then + return false + end + return true +end + local function clearSelectedItem() if selectedItem and selectedItem.item.ptr then Market.updateOffers({}) @@ -97,20 +150,19 @@ local function initMarketItems() local t = types[i] local newItem = Item.create(t:getId()) if newItem then - local item = { - ptr = newItem, - marketData = t:getMarketData() - } - marketItems[#marketItems+1] = item + local marketData = t:getMarketData() + if not table.empty(marketData) then + local item = { + ptr = newItem, + marketData = marketData + } + marketItems[#marketItems+1] = item + end end end end local function updateItemsWidget() - if table.empty(currentItems) then - return - end - itemsPanel = browsePanel:recursiveGetChildById('itemsPanel') local layout = itemsPanel:getLayout() layout:disableUpdates() @@ -138,25 +190,38 @@ local function updateItemsWidget() layout:update() end -local function loadDepotItems(depotItems) - information.depotItems = {} - for i = 1, #depotItems do - local data = depotItems[i] - local item = Item.create(data[1]) - if not item then - break - end - item:setCount(data[2]) - local marketData = item:getMarketData() +local function onUpdateCategory(combobox, option) + local id = getMarketCategoryId(option) + if id == MarketCategory.MetaWeapons then + -- enable and load weapons filter/items + subCategoryList:setEnabled(true) + slotFilterList:setEnabled(true) + local subId = getMarketCategoryId(subCategoryList:getCurrentOption().text) + Market.loadMarketItems(subId) + else + subCategoryList:setEnabled(false) + slotFilterList:setEnabled(false) + Market.loadMarketItems(id) -- load standard filter + end +end - if not table.empty(marketData) then - local newItem = { - ptr = item, - marketData = marketData - } - table.insert(information.depotItems, newItem) +local function onUpdateSubCategory(combobox, option) + local id = getMarketCategoryId(option) + Market.loadMarketItems(id) + -- setup slot filter + slotFilterList:clearOptions() + local subId = getMarketCategoryId(subCategoryList:getCurrentOption().text) + local slots = MarketCategoryWeapons[subId].slots + for _, slot in pairs(slots) do + if table.hasKey(MarketSlotFilters, slot) then + slotFilterList:addOption(MarketSlotFilters[slot]) end end + slotFilterList:setEnabled(true) +end + +local function onUpdateSlotFilter(combobox, option) + Market.updateCurrentItems() end local function initInterface() @@ -208,16 +273,33 @@ local function initInterface() selectedItem = marketOffersPanel:recursiveGetChildById('selectedItem') selectedItem.item = {} - -- populate filter combo box - filterBox = browsePanel:getChildById('filterComboBox') - for i = MarketCategory.First, MarketCategory.Last do - filterBox:addOption(getMarketCategoryName(i)) - end - filterBox:setCurrentOption(getMarketCategoryName(MarketCategory.First)) + -- setup filters + filterButtons[MarketFilters.Vocation] = browsePanel:getChildById('filterVocation') + filterButtons[MarketFilters.Level] = browsePanel:getChildById('filterLevel') + filterButtons[MarketFilters.Depot] = browsePanel:getChildById('filterDepot') - filterBox.onOptionChange = function(combobox, option) - Market.loadMarketItems(getMarketCategoryId(option)) + categoryList = browsePanel:getChildById('categoryComboBox') + subCategoryList = browsePanel:getChildById('subCategoryComboBox') + slotFilterList = browsePanel:getChildById('typeComboBox') + + slotFilterList:addOption(MarketSlotFilters[255]) + slotFilterList:setEnabled(false) + + for i = MarketCategory.First, MarketCategory.Last do + if i >= MarketCategory.Ammunition and i <= MarketCategory.WandsRods then + subCategoryList:addOption(getMarketCategoryName(i)) + else + categoryList:addOption(getMarketCategoryName(i)) + end end + categoryList:addOption(getMarketCategoryName(255)) -- meta weapons + categoryList:setCurrentOption(getMarketCategoryName(MarketCategory.First)) + subCategoryList:setEnabled(false) + + -- hook item filters + categoryList.onOptionChange = onUpdateCategory + subCategoryList.onOptionChange = onUpdateSubCategory + slotFilterList.onOptionChange = onUpdateSlotFilter -- get tables buyOfferTable = itemOffersPanel:recursiveGetChildById('buyingTable') @@ -242,48 +324,62 @@ function Market.terminate() end mainTabBar = nil - marketOffersPanel = nil + displaysTabBar = nil + offersTabBar = nil selectionTabBar = nil + + marketOffersPanel = nil browsePanel = nil searchPanel = nil - displaysTabBar = nil itemOffersPanel = nil itemDetailsPanel = nil itemStatsPanel = nil myOffersPanel = nil - offersTabBar = nil currentOffersPanel = nil offerHistoryPanel = nil - marketOffers = {} - marketItems = {} - depotItems = {} - information = {} - currentItems = {} itemsPanel = nil + nameLabel = nil + radioItemSet = nil + selectedItem = nil + categoryList = nil + subCategoryList = nil + slotFilterList = nil + filterButtons = {} + buyOfferTable = nil sellOfferTable = nil detailsTable = nil buyStatsTable = nil sellStatsTable = nil - radioItemSet = nil - selectedItem = nil - filterBox = nil + marketOffers = {} + marketItems = {} + information = {} + currentItems = {} + Market = nil end -function Market.loadMarketItems(_category) +function Market.depotContains(itemId) + for i = 1, #information.depotItems do + local item = information.depotItems[i] + if item.ptr:getId() == itemId then + return true + end + end + return false +end + +function Market.loadMarketItems(category) if table.empty(marketItems) then initMarketItems() end currentItems = {} for i = 1, #marketItems do - -- filter items here local item = marketItems[i] - local category = item.marketData.category - if category == _category or _category == MarketCategory[0] then + if isValidItem(item, category) then table.insert(currentItems, item) end end @@ -291,6 +387,36 @@ function Market.loadMarketItems(_category) updateItemsWidget() end +function Market.loadDepotItems(depotItems) + information.depotItems = {} + for i = 1, #depotItems do + local data = depotItems[i] + local newItem = Item.create(data[1]) + if not newItem then + break + end + newItem:setCount(data[2]) + local marketData = newItem:getMarketData() + + if not table.empty(marketData) then + local item = { + ptr = newItem, + marketData = marketData + } + table.insert(information.depotItems, item) + end + end +end + +function Market.updateCurrentItems() + -- get market category + local id = getMarketCategoryId(categoryList:getCurrentOption().text) + if id == MarketCategory.MetaWeapons then + id = getMarketCategoryId(subCategoryList:getCurrentOption().text) + end + Market.loadMarketItems(id) +end + function Market.updateOffers(offers) marketOffers[MarketAction.Buy] = {} marketOffers[MarketAction.Sell] = {} @@ -330,7 +456,6 @@ function Market.updateDetails(itemId, descriptions, purchaseStats, saleStats) return end selectedItem.item.details = { - serverItemId = itemId, descriptions = descriptions, purchaseStats = purchaseStats, saleStats = saleStats @@ -340,7 +465,7 @@ function Market.updateDetails(itemId, descriptions, purchaseStats, saleStats) detailsTable:clearData() for k, desc in pairs(descriptions) do local columns = { - {['text'] = getMarketDescriptionName(desc[1])..':', ['width'] = 100}, + {['text'] = getMarketDescriptionName(desc[1])..':'}, {['text'] = desc[2], ['width'] = 330} } detailsTable:addRow(columns) @@ -349,21 +474,20 @@ function Market.updateDetails(itemId, descriptions, purchaseStats, saleStats) -- update sale item statistics sellStatsTable:clearData() if table.empty(saleStats) then - sellStatsTable:addRow({{['text'] = 'No information', ['width'] = 110}}) + sellStatsTable:addRow({{['text'] = 'No information'}}) else for k, stat in pairs(saleStats) do if not table.empty(stat) then - sellStatsTable:addRow({{['text'] = 'Total Transations:', ['width'] = 110}, + sellStatsTable:addRow({{['text'] = 'Total Transations:'}, {['text'] = stat[1], ['width'] = 270}}) - sellStatsTable:addRow({{['text'] = 'Highest Price:', ['width'] = 110}, + sellStatsTable:addRow({{['text'] = 'Highest Price:'}, {['text'] = stat[3], ['width'] = 270}}) - print(stat[2] .. '/' ..stat[1]) - sellStatsTable:addRow({{['text'] = 'Average Price:', ['width'] = 110}, - {['text'] = math.floor(stat[2]/stat[1]), ['width'] = 270}}) + sellStatsTable:addRow({{['text'] = 'Average Price:'}, + {['text'] = math.floor(stat[2]/stat[1])}}) - sellStatsTable:addRow({{['text'] = 'Lowest Price:', ['width'] = 110}, + sellStatsTable:addRow({{['text'] = 'Lowest Price:'}, {['text'] = stat[4], ['width'] = 270}}) end end @@ -372,21 +496,20 @@ function Market.updateDetails(itemId, descriptions, purchaseStats, saleStats) -- update buy item statistics buyStatsTable:clearData() if table.empty(purchaseStats) then - buyStatsTable:addRow({{['text'] = 'No information', ['width'] = 110}}) + buyStatsTable:addRow({{['text'] = 'No information'}}) else for k, stat in pairs(purchaseStats) do if not table.empty(stat) then - buyStatsTable:addRow({{['text'] = 'Total Transations:', ['width'] = 110}, + buyStatsTable:addRow({{['text'] = 'Total Transations:'}, {['text'] = stat[1], ['width'] = 270}}) - buyStatsTable:addRow({{['text'] = 'Highest Price:', ['width'] = 110}, + buyStatsTable:addRow({{['text'] = 'Highest Price:'}, {['text'] = stat[3], ['width'] = 270}}) - print(stat[2] .. '/' ..stat[1]) - buyStatsTable:addRow({{['text'] = 'Average Price:', ['width'] = 110}, + buyStatsTable:addRow({{['text'] = 'Average Price:'}, {['text'] = math.floor(stat[2]/stat[1]), ['width'] = 270}}) - buyStatsTable:addRow({{['text'] = 'Lowest Price:', ['width'] = 110}, + buyStatsTable:addRow({{['text'] = 'Lowest Price:'}, {['text'] = stat[4], ['width'] = 270}}) end end @@ -399,7 +522,7 @@ function Market.updateSelectedItem(newItem) if selectedItem.item.ptr then selectedItem:setItem(selectedItem.item.ptr) nameLabel:setText(selectedItem.item.marketData.name) - MarketProtocol.sendMarketBrowse(selectedItem.item.ptr:getId()) -- send sprite id browsed + MarketProtocol.sendMarketBrowse(selectedItem.item.ptr:getId()) -- send browsed msg end else selectedItem:setItem(nil) @@ -407,21 +530,32 @@ function Market.updateSelectedItem(newItem) end end -function Market.onMarketEnter(depotItems, offers, balance) +function Market.onMarketEnter(depotItems, offers, balance, vocation) if marketWindow:isVisible() then return end - marketWindow:lock() marketOffers[MarketAction.Buy] = {} marketOffers[MarketAction.Sell] = {} + --[[ + TODO: + * clear filters on enter + * add market reset function + ]] information.balance = balance information.totalOffers = offers + if vocation < 0 then + local player = g_game.getLocalPlayer() + if player then information.vocation = player:getVocation() end + else + -- vocation must be compatible with < 950 + information.vocation = vocation + end if table.empty(currentItems) then Market.loadMarketItems(MarketCategory.First) end - loadDepotItems(depotItems) + Market.loadDepotItems(depotItems) -- build offer table header if buyOfferTable and not buyOfferTable:hasHeader() then @@ -436,6 +570,8 @@ function Market.onMarketEnter(depotItems, offers, balance) -- Uncheck selected item, cannot make protocol calls to resend marketBrowsing clearSelectedItem() end + + marketWindow:lock() marketWindow:show() end diff --git a/modules/game_market/marketprotocol.lua b/modules/game_market/marketprotocol.lua index 8aa12644..c297a116 100644 --- a/modules/game_market/marketprotocol.lua +++ b/modules/game_market/marketprotocol.lua @@ -37,8 +37,9 @@ end -- parsing protocols local function parseMarketEnter(msg) local balance = msg:getU32() + local vocation = -1 if g_game.getProtocolVersion() < 950 then - msg:getU8() -- get vocation id + vocation = msg:getU8() -- get vocation id end local offers = msg:getU8() local depotItems = {} @@ -51,7 +52,7 @@ local function parseMarketEnter(msg) table.insert(depotItems, {itemId, itemCount}) end - signalcall(Market.onMarketEnter, depotItems, offers, balance) + signalcall(Market.onMarketEnter, depotItems, offers, balance, vocation) return true end diff --git a/modules/game_market/ui/general/marketbuttons.otui b/modules/game_market/ui/general/marketbuttons.otui index 35215e4c..a73124a9 100644 --- a/modules/game_market/ui/general/marketbuttons.otui +++ b/modules/game_market/ui/general/marketbuttons.otui @@ -1,6 +1,6 @@ MarketButtonBox < UICheckBox font: verdana-11px-antialised - color: #f55e5ecc + color: #f55e5ebb size: 106 22 text-offset: 0 0 text-align: center diff --git a/modules/game_market/ui/marketoffers/browse.otui b/modules/game_market/ui/marketoffers/browse.otui index cd059bc2..143f50d7 100644 --- a/modules/game_market/ui/marketoffers/browse.otui +++ b/modules/game_market/ui/marketoffers/browse.otui @@ -28,7 +28,7 @@ Panel margin: 1 MarketComboBox - id: filterComboBox + id: categoryComboBox anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right @@ -37,7 +37,7 @@ Panel margin-left: 3 MarketComboBox - id: weaponComboBox + id: subCategoryComboBox anchors.top: prev.bottom anchors.left: parent.left anchors.right: parent.right @@ -45,8 +45,11 @@ Panel margin-right: 3 margin-left: 3 + $disabled: + color: #aaaaaa44 + MarketButtonBox - id: filterMatchLevel + id: filterLevel checked: false !text: tr('Level') !tooltip: tr('Filter list to match your level') @@ -57,20 +60,20 @@ Panel margin-left: 3 width: 40 height: 20 - //@onClick: Market.filterMatchLevel() + @onCheckChange: Market.updateCurrentItems() MarketButtonBox - id: filterMatchVocation + id: filterVocation checked: false - !text: tr('Vocation') + !text: tr('Voc.') !tooltip: tr('Filter list to match your vocation') anchors.top: prev.top anchors.left: prev.right margin-right: 3 margin-left: 3 - width: 60 + width: 34 height: 20 - //@onClick: Market.filterMatchVocation() + @onCheckChange: Market.updateCurrentItems() MarketComboBox id: typeComboBox @@ -80,8 +83,11 @@ Panel margin-right: 3 margin-left: 3 + $disabled: + color: #aaaaaa44 + MarketButtonBox - id: showDepotOnly + id: filterDepot checked: false !text: tr('Show Depot Only') !tooltip: tr('Show your depot items only') @@ -91,7 +97,7 @@ Panel margin-top: 6 margin-right: 3 margin-left: 3 - //@onClick: Market.setDisplayDepot() + @onCheckChange: Market.updateCurrentItems() Panel anchors.top: prev.bottom diff --git a/modules/game_market/ui/marketoffers/itemdetails.otui b/modules/game_market/ui/marketoffers/itemdetails.otui index 0442fc43..33de5a22 100644 --- a/modules/game_market/ui/marketoffers/itemdetails.otui +++ b/modules/game_market/ui/marketoffers/itemdetails.otui @@ -12,7 +12,7 @@ DetailsTableColumn < TableColumn background-color: alpha text-offset: 5 2 color: #cccccc - width: 80 + width: 100 focusable: false Panel @@ -27,7 +27,7 @@ Panel anchors.right: parent.right margin-top: 55 margin-left: 6 - margin-bottom: 45 + margin-bottom: 75 margin-right: 6 padding: 1 focusable: false diff --git a/modules/game_market/ui/marketoffers/itemstats.otui b/modules/game_market/ui/marketoffers/itemstats.otui index 5b93866b..5f2f3d9e 100644 --- a/modules/game_market/ui/marketoffers/itemstats.otui +++ b/modules/game_market/ui/marketoffers/itemstats.otui @@ -11,7 +11,7 @@ StatsTableColumn < TableColumn background-color: alpha text-offset: 5 0 color: #cccccc - width: 80 + width: 110 focusable: false Panel diff --git a/modules/gamelib/market.lua b/modules/gamelib/market.lua index e7afcd54..b90ea060 100644 --- a/modules/gamelib/market.lua +++ b/modules/gamelib/market.lua @@ -28,6 +28,15 @@ MarketCategory = { MarketCategory.First = MarketCategory.Armors MarketCategory.Last = MarketCategory.PremiumScrolls +MarketCategoryWeapons = { + [MarketCategory.Ammunition] = { slots = {255} }, + [MarketCategory.Axes] = { slots = {255, InventorySlotOther, InventorySlotLeft} }, + [MarketCategory.Clubs] = { slots = {255, InventorySlotOther, InventorySlotLeft} }, + [MarketCategory.DistanceWeapons] = { slots = {255, InventorySlotOther, InventorySlotLeft} }, + [MarketCategory.Swords] = { slots = {255, InventorySlotOther, InventorySlotLeft} }, + [MarketCategory.WandsRods] = { slots = {255, InventorySlotOther, InventorySlotLeft} } +} + MarketCategoryStrings = { [0] = 'All', [1] = 'Armors', @@ -52,7 +61,7 @@ MarketCategoryStrings = { [20] = 'Swords', [21] = 'Wands and Rods', [22] = 'Premium Scrolls', - [255] = 'Meta Weapons' + [255] = 'Weapons' } MarketAction = { @@ -90,6 +99,7 @@ MarketItemDescription = { WeaponName = 14, Weight = 15 } + MarketItemDescription.First = MarketItemDescription.Armor MarketItemDescription.Last = MarketItemDescription.Weight @@ -110,3 +120,18 @@ MarketItemDescriptionStrings = { [14] = 'Weapon Type', [15] = 'Weight' } + +MarketSlotFilters = { + [InventorySlotOther] = "Two-Handed", + [InventorySlotLeft] = "One-Handed", + [255] = "Any" +} + +MarketFilters = { + Vocation = 1, + Level = 2, + Depot = 3 +} + +MarketFilters.First = MarketFilters.vocation +MarketFilters.Last = MarketFilters.depot \ No newline at end of file diff --git a/modules/gamelib/player.lua b/modules/gamelib/player.lua index eee5a9cf..d5538f49 100644 --- a/modules/gamelib/player.lua +++ b/modules/gamelib/player.lua @@ -1,5 +1,6 @@ -- @docclass Player +InventorySlotOther = 0 InventorySlotHead = 1 InventorySlotNeck = 2 InventorySlotBack = 3 diff --git a/src/otclient/localplayer.cpp b/src/otclient/localplayer.cpp index 108c072b..755d24e4 100644 --- a/src/otclient/localplayer.cpp +++ b/src/otclient/localplayer.cpp @@ -33,7 +33,10 @@ LocalPlayer::LocalPlayer() m_lastPrewalkDone = true; m_autoWalking = false; m_known = false; + m_premium = false; + m_states = 0; + m_vocation = 0; m_skillsLevel.fill(-1); m_skillsLevelPercent.fill(-1); @@ -327,3 +330,22 @@ void LocalPlayer::setInventoryItem(Otc::InventorySlot inventory, const ItemPtr& callLuaField("onInventoryChange", inventory, item, oldItem); } } + +void LocalPlayer::setVocation(int vocation) +{ + if(m_vocation != vocation) { + int oldVocation = m_vocation; + m_vocation = vocation; + + callLuaField("onVocationChange", vocation, oldVocation); + } +} + +void LocalPlayer::setPremium(bool premium) +{ + if(m_premium != premium) { + m_premium = premium; + + callLuaField("onPremiumChange", premium); + } +} diff --git a/src/otclient/localplayer.h b/src/otclient/localplayer.h index 314f9b20..8fa3b207 100644 --- a/src/otclient/localplayer.h +++ b/src/otclient/localplayer.h @@ -52,10 +52,13 @@ public: void setStamina(double stamina); void setKnown(bool known) { m_known = known; } void setInventoryItem(Otc::InventorySlot inventory, const ItemPtr& item); + void setVocation(int vocation); + void setPremium(bool premium); int getStates() { return m_states; } int getSkillLevel(Otc::Skill skill) { return m_skillsLevel[skill]; } int getSkillLevelPercent(Otc::Skill skill) { return m_skillsLevelPercent[skill]; } + int getVocation() { return m_vocation; } double getHealth() { return m_health; } double getMaxHealth() { return m_maxHealth; } double getFreeCapacity() { return m_freeCapacity; } @@ -73,6 +76,7 @@ public: bool isKnown() { return m_known; } bool isPreWalking() { return m_preWalking; } bool isAutoWalking() { return m_autoWalking; } + bool isPremium() { return m_premium; } LocalPlayerPtr asLocalPlayer() { return std::static_pointer_cast(shared_from_this()); } bool isLocalPlayer() { return true; } @@ -96,6 +100,7 @@ private: bool m_lastPrewalkDone; bool m_walkLocked; bool m_autoWalking; + bool m_premium; Position m_lastPrewalkDestionation; Timer m_walkLockTimer; ItemPtr m_inventoryItems[Otc::LastInventorySlot]; @@ -106,6 +111,7 @@ private: bool m_known; int m_states; + int m_vocation; double m_health; double m_maxHealth; diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 2d8119ac..45b811e3 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -350,7 +350,8 @@ void OTClient::registerLuaFunctions() 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.bindClassMemberFunction("getMarketData", &Item::getMarketData); + g_lua.bindClassMemberFunction("getClothSlot", &Item::getClothSlot); g_lua.registerClass(); g_lua.registerClass(); @@ -393,6 +394,8 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("getSoul", &LocalPlayer::getSoul); g_lua.bindClassMemberFunction("getStamina", &LocalPlayer::getStamina); g_lua.bindClassMemberFunction("getInventoryItem", &LocalPlayer::getInventoryItem); + g_lua.bindClassMemberFunction("getVocation", &LocalPlayer::getVocation); + g_lua.bindClassMemberFunction("isPremium", &LocalPlayer::isPremium); g_lua.bindClassMemberFunction("isKnown", &LocalPlayer::isKnown); g_lua.bindClassMemberFunction("isPreWalking", &LocalPlayer::isPreWalking); g_lua.bindClassMemberFunction("asLocalPlayer", &LocalPlayer::asLocalPlayer); diff --git a/src/otclient/luavaluecasts.cpp b/src/otclient/luavaluecasts.cpp index 16f91fb2..40e2a1b6 100644 --- a/src/otclient/luavaluecasts.cpp +++ b/src/otclient/luavaluecasts.cpp @@ -107,8 +107,8 @@ int push_luavalue(const MarketData& data) 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.restrictVocation); + g_lua.setField("restrictVocation"); g_lua.pushInteger(data.showAs); g_lua.setField("showAs"); g_lua.pushInteger(data.tradeAs); @@ -125,8 +125,8 @@ bool luavalue_cast(int index, MarketData& data) 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("restrictVocation", index); + data.restrictVocation = g_lua.popInteger(); g_lua.getField("showAs", index); data.showAs = g_lua.popInteger(); g_lua.getField("tradeAs", index); diff --git a/src/otclient/protocolcodes.h b/src/otclient/protocolcodes.h index 0dbbad4b..f2b2dfbb 100644 --- a/src/otclient/protocolcodes.h +++ b/src/otclient/protocolcodes.h @@ -98,7 +98,7 @@ namespace Proto { GameServerCreatureUnpass = 146, GameServerEditText = 150, GameServerEditList = 151, - GameServerPlayerDataBasic = 159, // 910 + GameServerPlayerDataBasic = 159, // 950 GameServerPlayerData = 160, GameServerPlayerSkills = 161, GameServerPlayerState = 162, diff --git a/src/otclient/protocolgameparse.cpp b/src/otclient/protocolgameparse.cpp index 0f5b3742..25070c3f 100644 --- a/src/otclient/protocolgameparse.cpp +++ b/src/otclient/protocolgameparse.cpp @@ -288,9 +288,6 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) parseMultiUseDelay(msg); break; // PROTOCOL>=910 - case Proto::GameServerPlayerDataBasic: - parsePlayerInfo(msg); - break; case Proto::GameServerChannelEvent: parseChannelEvent(msg); break; @@ -300,6 +297,10 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) case Proto::GameServerPlayerInventory: parsePlayerInventory(msg); break; + // PROTOCOL>=950 + case Proto::GameServerPlayerDataBasic: + parsePlayerInfo(msg); + break; // otclient ONLY case Proto::GameServerExtendedOpcode: parseExtendedOpcode(msg); @@ -832,12 +833,15 @@ void ProtocolGame::parseEditList(const InputMessagePtr& msg) void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg) { - msg->getU8(); // is premium? - msg->getU8(); // profession - int numSpells = msg->getU16(); - for(int i=0;igetU16(); // spell id + bool premium = msg->getU8(); // premium + int vocation = msg->getU8(); // vocation + int spellCount = msg->getU16(); + for(int i=0;igetU16(); // spell id - TODO: add to local player } + + m_localPlayer->setPremium(premium); + m_localPlayer->setVocation(vocation); } void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg) @@ -1221,7 +1225,13 @@ void ProtocolGame::parseChannelEvent(const InputMessagePtr& msg) void ProtocolGame::parseItemInfo(const InputMessagePtr& msg) { - //TODO + /*int count = msg.getU16() - 1; + for(int i = 0; i < count; i++) + { + int unknown1 = msg->getU8(); + int unknown2 = msg->getU16(); + std::string unknown3 = msg->getString(); + }*/ } void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg) diff --git a/src/otclient/thingtype.cpp b/src/otclient/thingtype.cpp index 919fa834..568bad1d 100644 --- a/src/otclient/thingtype.cpp +++ b/src/otclient/thingtype.cpp @@ -83,7 +83,7 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS market.tradeAs = fin->getU16(); market.showAs = fin->getU16(); market.name = fin->getString(); - market.restrictProfession = fin->getU16(); + market.restrictVocation = fin->getU16(); market.requiredLevel = fin->getU16(); m_attribs.set(attr, market); break; diff --git a/src/otclient/thingtype.h b/src/otclient/thingtype.h index 95824966..7f6539cb 100644 --- a/src/otclient/thingtype.h +++ b/src/otclient/thingtype.h @@ -76,7 +76,7 @@ enum ThingAttr : uint8 { ThingAttrCloth = 32, ThingAttrMarket = 33, ThingAttrChargeable = 254, // deprecated - ThingLastAttr = 255, + ThingLastAttr = 255 }; enum SpriteMask { @@ -90,7 +90,7 @@ struct MarketData { std::string name; int category; uint16 requiredLevel; - uint16 restrictProfession; + uint16 restrictVocation; uint16 showAs; uint16 tradeAs; };