Market item filtering improvements and other some minor improvements

* Can now filter market items by vocation, level, slot type, and depot items.
* Added new bitwise lib for handling flag operations.
* Can now get/set local player vocation/premium (TODO: spell list).
This commit is contained in:
BeniS 2012-07-24 03:11:53 +12:00
parent dc8ef845ab
commit 19dd96fd02
21 changed files with 369 additions and 116 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -9,6 +9,7 @@ Module
dofile 'math'
dofile 'string'
dofile 'table'
dofile 'bitwise'
dofile 'const'
dofile 'util'

View File

@ -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

View File

@ -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 marketData = t:getMarketData()
if not table.empty(marketData) then
local item = {
ptr = newItem,
marketData = t:getMarketData()
marketData = marketData
}
marketItems[#marketItems+1] = item
end
end
end
local function updateItemsWidget()
if table.empty(currentItems) then
return
end
local function updateItemsWidget()
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
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
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)
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

View File

@ -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

View File

@ -1,6 +1,6 @@
MarketButtonBox < UICheckBox
font: verdana-11px-antialised
color: #f55e5ecc
color: #f55e5ebb
size: 106 22
text-offset: 0 0
text-align: center

View File

@ -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

View File

@ -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

View File

@ -11,7 +11,7 @@ StatsTableColumn < TableColumn
background-color: alpha
text-offset: 5 0
color: #cccccc
width: 80
width: 110
focusable: false
Panel

View File

@ -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

View File

@ -1,5 +1,6 @@
-- @docclass Player
InventorySlotOther = 0
InventorySlotHead = 1
InventorySlotNeck = 2
InventorySlotBack = 3

View File

@ -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);
}
}

View File

@ -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<LocalPlayer>(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;

View File

@ -350,7 +350,8 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassMemberFunction<Item>("getId", &Item::getId);
g_lua.bindClassMemberFunction<Item>("isStackable", &Item::isStackable);
g_lua.bindClassMemberFunction<Item>("isMarketable", &Item::isMarketable);
g_lua.bindClassMemberFunction<Item>("getMarketData", &Item::isMarketable);
g_lua.bindClassMemberFunction<Item>("getMarketData", &Item::getMarketData);
g_lua.bindClassMemberFunction<Item>("getClothSlot", &Item::getClothSlot);
g_lua.registerClass<Effect, Thing>();
g_lua.registerClass<Missile, Thing>();
@ -393,6 +394,8 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassMemberFunction<LocalPlayer>("getSoul", &LocalPlayer::getSoul);
g_lua.bindClassMemberFunction<LocalPlayer>("getStamina", &LocalPlayer::getStamina);
g_lua.bindClassMemberFunction<LocalPlayer>("getInventoryItem", &LocalPlayer::getInventoryItem);
g_lua.bindClassMemberFunction<LocalPlayer>("getVocation", &LocalPlayer::getVocation);
g_lua.bindClassMemberFunction<LocalPlayer>("isPremium", &LocalPlayer::isPremium);
g_lua.bindClassMemberFunction<LocalPlayer>("isKnown", &LocalPlayer::isKnown);
g_lua.bindClassMemberFunction<LocalPlayer>("isPreWalking", &LocalPlayer::isPreWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("asLocalPlayer", &LocalPlayer::asLocalPlayer);

View File

@ -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);

View File

@ -98,7 +98,7 @@ namespace Proto {
GameServerCreatureUnpass = 146,
GameServerEditText = 150,
GameServerEditList = 151,
GameServerPlayerDataBasic = 159, // 910
GameServerPlayerDataBasic = 159, // 950
GameServerPlayerData = 160,
GameServerPlayerSkills = 161,
GameServerPlayerState = 162,

View File

@ -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;i<numSpells;++i) {
msg->getU16(); // spell id
bool premium = msg->getU8(); // premium
int vocation = msg->getU8(); // vocation
int spellCount = msg->getU16();
for(int i=0;i<spellCount;++i) {
int spellId = msg->getU16(); // 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)

View File

@ -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;

View File

@ -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;
};