AuctioneerSuite/Informant/InfMain.lua
2026-04-13 17:48:13 -04:00

1250 lines
36 KiB
Lua

--[[
Informant - An addon for World of Warcraft that shows pertinent information about
an item in a tooltip when you hover over the item in the game.
Version: 5.9.4961 (WhackyWallaby)
Revision: $Id: InfMain.lua 4880 2010-09-15 20:02:11Z Nechckn $
URL: http://auctioneeraddon.com/dl/Informant/
License:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program(see GPL.txt); if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Note:
This AddOn's source code is specifically designed to work with
World of Warcraft's interpreted AddOn system.
You have an implicit license to use this AddOn with these facilities
since that is its designated purpose as per:
http://www.fsf.org/licensing/licenses/gpl-faq.html#InterpreterIncompat
]]
Informant_RegisterRevision("$URL: http://svn.norganna.org/auctioneer/branches/5.9/Informant/InfMain.lua $","$Rev: 4880 $")
INFORMANT_VERSION = "5.9.4961"
if (INFORMANT_VERSION == "<".."%version%>") then
INFORMANT_VERSION = "5.2.DEV"
end
local _G=_G
local type,pairs,ipairs,select = type,pairs,ipairs,select
local tonumber,tostring,strmatch = tonumber,tostring,strmatch
local strsplit,strsub,format = strsplit,strsub,format
local tinsert,wipe = tinsert,wipe
local GetItemInfo = GetItemInfo
local Informant
-- GLOBALS: INFORMANT_VERSION, _TRANS, this, LibStub
-- GLOBALS: InformantLocalUpdates, InformantConfig
-- GLOBALS: InformantFrame, InformantFrameScrollBar
-- GLOBALS: UIParent, MerchantFrame
-- GLOBALS: UnitGUID, UnitFactionGroup, UnitName
-- GLOBALS: InRepairMode, GetMerchantItemLink, GetMerchantItemInfo, GetMerchantNumItems
-- LOCAL FUNCTION PROTOTYPES:
local addLine -- addLine(text, color)
local clear -- clear()
local debugPrint -- debugPrint(message, title, errorCode, level)
local frameActive -- frameActive(isActive)
local frameLoaded -- frameLoaded()
local getCatName -- getCatName(catID)
local getItem -- getItem(itemID)
local getLocale
local getRowCount -- getRowCount()
local infDebugPrint -- debugPrint(message, category, title, errorCode, level)
local onEvent -- onEvent(event)
local onLoad -- onLoad()
local onVariablesLoaded -- onVariablesLoaded()
local onQuit -- onQuit()
local scrollUpdate -- scrollUpdate(offset)
local setDatabase -- setDatabase(database)
local setRequirements -- setRequirements(requirements)
local setSkills -- setSkills(skills)
local setVendors -- setVendors(vendors)
local setVendorLocation -- setVendorLocation(vendors)
local setQuestStarts
local setQuestRequires
local setQuestRewards
local setQuestNames
local setZones --
local setCrafted -- setCrafted(crafted)
local setCraftCount -- setCraftCount(craft_counts)
local showHideInfo -- showHideInfo()
local skillToName -- skillToName(userSkill)
local split -- split(str, at)
local Dump
local debugPrintQuick
local idFromLink
local OnTooltipAddMoney
-- LOCAL VARIABLES
local self = {}
local lines = {}
local addonName = "Informant"
local tooltip = LibStub("nTipHelper:1")
-- GLOBAL VARIABLES
BINDING_HEADER_INFORMANT_HEADER = _TRANS('INF_Interface_BindingHeader')
BINDING_NAME_INFORMANT_POPUPDOWN = _TRANS('INF_Interface_BindingTitle')
InformantConfig = {}
-- LOCAL DEFINES
CLASS_TO_CATEGORY_MAP = {
[2] = 1, --Weapon
[4] = 2, --Armor
[1] = 3, --Container
[0] = 4, --Consumable
[16] = 5, --Glyph
[7] = 6, --Trade Goods
[6] = 7, --Projectile
[11] = 8, --Quiver
[9] = 9, --Recipe
[3] = 10, --Gem
[10] = 11, --Miscellaneous(Currency)
[15] = 11, --Miscellaneous
[13] = 11, --Miscellaneous
[5] = 11, --Miscellaneous
[12] = 12, --Quest
}
-- FUNCTION DEFINITIONS
function split(str, at)
if (not (type(str) == "string")) then
return
end
if (not str) then
str = ""
end
if (not at) then
return {str}
else
return {strsplit(at, str)};
end
end
-- utility, so we don't have to maintain multiple copies of this
function idFromLink( itemLink )
return tonumber(strmatch(itemLink, "item:(%d+)"))
end
function skillToName(userSkill)
local skillName = self.skills[tonumber(userSkill)]
local localized = "Unknown"
if (skillName) then
localized = _TRANS('INF_Tooltip_Skill'..skillName) or "Unknown: "..skillName
end
return localized, skillName
end
local staticDataItem={}
local emptyTable={}
local staticDataID
local cache = setmetatable({}, {__mode="v"})
function getItem(itemID, static)
if (not itemID) then return end
if (static and staticDataID and staticDataID==itemID) then return staticDataItem end
if cache[itemID] then return cache[itemID] end
local baseData = self.database[itemID]
local buy, class, quality, stack, additional, usedby, quantity, limited, merchantlist
local itemName, itemLink, itemQuality, itemLevel, itemUseLevel, itemType, itemSubType, itemStackSize, itemEquipLoc, itemTexture = GetItemInfo(tonumber(itemID))
if (baseData) then
buy, class, quality, stack, additional, usedby, quantity, limited, merchantlist = strsplit(":", baseData)
buy = tonumber(buy)
end
-- work around a blizzard bug where honor tokens return stack size 2147483647
-- this only seems to happen for the obsolete honor tokens shown in the currency frame
-- See JIRA INF-41
if (itemStackSize == 2147483647) then
itemStackSize = nil
stack = nil
end
-- if we have a local correction for this item, merge in the corrected data
local itemUpdateData
if (InformantLocalUpdates and InformantLocalUpdates.items) then
itemUpdateData = InformantLocalUpdates.items[ itemID ]
if (itemUpdateData) then
if (itemUpdateData.buy) then
buy = tonumber(itemUpdateData.buy)
end
if (itemUpdateData.sell) then
sell = tonumber(itemUpdateData.sell)
end
if (itemUpdateData.stack) then
stack = tonumber(itemUpdateData.stack)
end
if (itemUpdateData.quantity) then
quantity = tonumber(itemUpdateData.quantity)
end
end
end
class = tonumber(class)
quality = tonumber(quality) or itemQuality
stack = tonumber(itemStackSize) or tonumber(stack)
local cat = CLASS_TO_CATEGORY_MAP[class]
sell = select(11,GetItemInfo(itemID))
local dataItem = (static and staticDataItem or {})
dataItem.buy = buy
dataItem.sell = sell
dataItem.class = class
dataItem.classText = itemType
dataItem.cat = cat
dataItem.quality = quality
dataItem.stack = stack
dataItem.additional = additional
dataItem.usedby = usedby
dataItem.quantity = quantity
dataItem.limited = limited
dataItem.texture = itemTexture
dataItem.itemLevel = itemLevel
dataItem.reqLevel = itemUseLevel
local addition = ""
if (additional and additional ~= "") then
addition = " - ".._TRANS('INF_Tooltip_Addit'..additional)
end
local catName = getCatName(cat)
if (not catName) then
if (itemType) then
dataItem.classText = itemType..addition
else
dataItem.classText = "Unknown"..addition
end
else
dataItem.classText = catName..addition
end
if (usedby and usedby ~= '') then
local usedList = split(usedby, ",")
local skillName, localized, localeString
local usage = ""
dataItem.usedList = {}
if (usedList) then
for pos, userSkill in pairs(usedList) do
localized = skillToName(userSkill)
if (usage == "") then
usage = localized
else
usage = usage .. ", " .. localized
end
tinsert(dataItem.usedList, localized)
end
end
dataItem.usageText = usage
else
dataItem.usedList = nil
dataItem.usageText = nil
end
local tradeSkillCode = 0
local tradeSkillLevel = 0
local tradeSkillName = ""
local skillsRequired = self.requirements[itemID]
if (skillsRequired) then
tradeSkillCode, tradeSkillLevel = strsplit(":", skillsRequired)
tradeSkillName = skillToName(tradeSkillCode)
end
dataItem.isPlayerMade = (tradeSkillCode ~= 0)
dataItem.tradeSkillLevel = tradeSkillLevel
dataItem.tradeSkillCode = tradeSkillCode
dataItem.tradeSkillName = tradeSkillName
if (merchantlist ~= '') then
local merchList = split(merchantlist, ",")
if (itemUpdateData and itemUpdateData.merchants) then
-- check update list for additional merchants
local moreMerch = split(itemUpdateData.merchants, ",")
if (#moreMerch > 0 and not merchList) then merchList = {} end
for pos, merchID in pairs(moreMerch) do
tinsert(merchList, merchID)
end
end
local vendList = {}
local vendLoc = {}
if (merchList) then
for pos, merchID in pairs(merchList) do
merchID = tonumber(merchID)
local vendName = self.vendors[ merchID ]
if (not vendName and InformantLocalUpdates and InformantLocalUpdates.vendor) then
-- can't find it, try the update list
local vendorInfo = InformantLocalUpdates.vendor[ merchID ]
if (vendorInfo) then
vendName = vendorInfo.name
end
end
if (vendName) then
tinsert(vendList, vendName)
local zone,xloc,yloc
if self.vendorLocation[merchID] then
zone,xloc,yloc = strsplit(",",self.vendorLocation[merchID])
end
if zone then
local location
zone = tonumber(zone)
if self.infZones[zone] then
zone = self.infZones[zone]
end
location = zone
if xloc and yloc then
location = location.." ("..xloc..","..yloc..")"
end
vendLoc[vendName] = location
else
vendLoc[vendName] = "No set location for this vendor"
end
end
end
end
dataItem.merchantList = merchList
dataItem.vendors = vendList
dataItem.vendorLoc = vendLoc
else
dataItem.merchantList = nil
dataItem.vendors = nil
end
dataItem.startsQuest = self.questStarts[itemID]
local questItemUse = self.questRequires[itemID]
if (questItemUse) then
local list
if (type(questItemUse) == 'number') then
list = { questItemUse }
else
list = { strsplit(',', questItemUse) }
end
for i=1, #list do
list[i] = { strsplit('x', list[i]) }
list[i][1] = tonumber(list[i][1])
if not list[i][2] then list[i][2] = 1 end
end
dataItem.requiredFor = list
else
dataItem.requiredFor = (static and emptyTable or {})
end
questItemUse = self.questRewards[itemID]
if (questItemUse) then
local list
if (type(questItemUse) == 'number') then
list = { questItemUse }
else
list = { strsplit(',', questItemUse) }
end
for i=1, #list do
list[i] = tonumber(list[i])
end
dataItem.rewardFrom = list
else
dataItem.rewardFrom = (static and emptyTable or {})
end
-- see if this is a recipe, and what it might create
if (self.crafted) then
local recipe_number = tonumber(itemID)
local crafted_item = self.crafted[ recipe_number ]
if (crafted_item) then
dataItem.crafts = crafted_item
-- see if it crafts more than 1 at a time
if (self.craftCount) then
local crafted_count = self.craftCount[ recipe_number ]
dataItem.craftsCount = crafted_count or 1
end
end
end
-- we adjusted the static table, if called with static = true
-- so save the itemID for future calls
if static then
staticDataID = itemID
else
cache[itemID] = dataItem
end
return dataItem
end
local function getInformantVendorInfo(id)
local isVendored,isLimited,itemCost,toSell,buyStack,maxStack
local itemID = tonumber(id)
local itemData = getItem(itemID)
if itemData.merchantList then
isVendored = true
else
isVendored = false
end
local itemLimited = itemData.limited
if itemLimited and tonumber(itemLimited) > 0 then
isLimited = true
else
isLimited = false
end
itemCost = tonumber(itemData.buy) or 0
toSell = tonumber(itemData.sell) or 0
buyStack = tonumber(itemData.quantity) or 1
maxStack = tonumber(itemData.stack) or 1
return isVendored,isLimited,itemCost,toSell,buyStack,maxStack
end
--Implementation of GetSellValue API proposed by Tekkub at http://www.wowwiki.com/API_GetSellValue
local origGetSellValue = GetSellValue
function GetSellValue(item)
local itemName, itemLink, _, _, _, _, _, _, _, _, itemSellPrice = GetItemInfo(item)
if itemSellPrice then
return itemSellPrice
end
local id
if type(item) == "number" then
id = item
elseif type(item) == "string" then
id = tonumber(strmatch(item, "item:(%d+)"))
if not id and itemLink then
id = tonumber(strmatch(itemLink, "item:(%d+)"))
end
end
-- Return out if we didn't find an id
if not id then return end
local itemInfo = Informant.GetItem(id)
local sellval
-- ccox - TODO - is this correct for items sold in stacks?
-- see Informant.TooltipHandler
if (itemInfo) then
sellval = itemInfo.sell
if (sellval) then
sellval = tonumber(sellval)
end
end
if sellval then
return sellval
elseif origGetSellValue then
-- Call our hook if present, pass the id to save processing it again
return origGetSellValue(id)
end
end
function setSkills(skills)
self.skills = skills
Informant.SetSkills = nil -- Set only once
end
function setRequirements(requirements)
self.requirements = requirements
Informant.SetRequirements = nil -- Set only once
end
function setVendors(vendors)
self.vendors = vendors
Informant.SetVendors = nil -- Set only once
end
function setDatabase(database)
self.database = database
Informant.SetDatabase = nil -- Set only once
end
function setQuestStarts(list)
self.questStarts = list
Informant.SetQuestStarts = nil -- Set only once
end
function setQuestRewards(list)
self.questRewards = list
Informant.SetQuestRewards = nil -- Set only once
end
function setQuestRequires(list)
self.questRequires = list
Informant.SetQuestRequires = nil -- Set only once
end
function setQuestNames(list)
self.questNames = list
Informant.SetQuestNames = nil -- Set only once
end
function setVendorLocation(list)
self.vendorLocation = list
Informant.SetVendorLocation = nil -- Set only once
end
function setZones(zones)
self.infZones = zones
Informant.zonestest = self.infZones
Informant.SetZones = nil -- Set only once
end
function setCrafted(crafted)
self.crafted = crafted
Informant.SetCrafted = nil -- Set only once
end
function setCraftCount(craft_counts)
self.craftCount = craft_counts
Informant.SetCraftCount = nil -- Set only once
end
function getLocale()
local locale = Informant.GetFilterVal('locale');
if (locale ~= 'on') and (locale ~= 'off') and (locale ~= 'default') then
return locale;
end
return GetLocale();
end
local categories = {GetAuctionItemClasses()};
function getCatName(catID)
for cat, name in ipairs(categories) do
if (cat == catID) then
return name
end
end
end
local function getQuestName(questID)
questID = tonumber(questID) or 0
local questName
if (self.questNames[questID]) then
questName = self.questNames[questID]
else
questName = _TRANS('INF_Interface_InfWinQuestUnknown'):format(questID)
end
-- format as just text, looks better
return "|cff5599ff"..questName
-- try to format as a link, but we don't make it clickable anywhere
-- if we want a linkable quest, we'll have to redo this
-- return "|HinfQuest:"..questID.."|h|cff5599ff["..questName.."]|r|h"
end
local function showItem(itemInfo)
if (itemInfo) then
InformantFrameTitle:SetText(_TRANS('INF_Interface_InfWinTitle'))
-- Woohoo! We need to provide any information we can from the item currently in itemInfo
local quality = itemInfo.itemQuality or itemInfo.quality or 0
local color = "ffffff"
if (quality == 4) then color = "a335ee"
elseif (quality == 3) then color = "0070dd"
elseif (quality == 2) then color = "1eff00"
elseif (quality == 0) then color = "9d9d9d"
end
clear()
addLine(_TRANS('INF_Interface_InfWinInfoHeader'):format(color, itemInfo.itemName))
local buy = itemInfo.itemBuy or itemInfo.buy or 0
local sell = itemInfo.itemSell or itemInfo.sell or 0
local quant = itemInfo.itemQuant or itemInfo.quantity or 0
local count = itemInfo.itemCount or 1
if ((buy > 0) or (sell > 0)) then
local bgsc = tooltip:Coins(buy)
local sgsc = tooltip:Coins(sell)
if (count and (count > 1)) then
local bqgsc = tooltip:Coins(buy*count)
local sqgsc = tooltip:Coins(sell*count)
addLine(_TRANS('INF_Tooltip_ShowVendorBuyMult'):format(count, bgsc)..": "..bqgsc, "ee8822")
addLine(_TRANS('INF_Tooltip_ShowVendorSellMult'):format(count, sgsc)..": "..sqgsc, "ee8822")
else
addLine(_TRANS('INF_Tooltip_ShowVendorBuy'):format()..": "..bgsc, "ee8822")
addLine(_TRANS('INF_Tooltip_ShowVendorSell'):format()..": "..sgsc, "ee8822")
end
end
if (itemInfo.stack and itemInfo.stack > 1) then
addLine(_TRANS('INF_Tooltip_StackSize'):format(itemInfo.stack))
end
local reagentInfo = ""
if (itemInfo.classText and itemInfo.classText ~= "") then
reagentInfo = _TRANS('INF_Tooltip_Class'):format(itemInfo.classText)
addLine(reagentInfo, "aa66ee")
end
if (itemInfo.usageText and itemInfo.usageText ~= "") then
reagentInfo = _TRANS('INF_Tooltip_Use'):format(itemInfo.usageText)
addLine(reagentInfo, "aa66ee")
end
if (itemInfo.isPlayerMade) then
addLine(_TRANS('INF_Interface_InfWinPlayerMade'):format(itemInfo.tradeSkillLevel, itemInfo.tradeSkillName), "5060ff")
end
local numReq = 0
local numRew = 0
local numSta = 0
if (itemInfo.startsQuest) then numSta = 1 end
if (itemInfo.requiredFor) then numReq = #itemInfo.requiredFor end
if (itemInfo.rewardFrom) then numRew = #itemInfo.rewardFrom end
local questCount = numReq + numRew + numSta
if (questCount > 0) then
addLine("")
addLine(_TRANS('INF_Interface_InfWinQuest'):format(questCount), nil, nil --[[TODO: this used to say: embed. what gives?!]])
if (numSta > 0) then
addLine(_TRANS('INF_Interface_InfWinQuestStart'), "70ee90")
addLine(" ".._TRANS('INF_Interface_InfWinQuestLine'):format(getQuestName(itemInfo.startsQuest)), "80ee80")
end
if (numRew > 0) then
addLine(_TRANS('INF_Interface_InfWinQuestReward'):format(numRew), "70ee90")
for i=1, numRew do
local quest = itemInfo.rewardFrom[i]
addLine(" ".._TRANS('INF_Interface_InfWinQuestLine'):format(getQuestName(quest)), "80ee80")
end
end
if (numReq > 0) then
addLine(_TRANS('INF_Interface_InfWinQuestRequires'):format(numReq), "70ee90")
for i=1, numReq do
local quest = itemInfo.requiredFor[i]
addLine(" ".._TRANS('INF_Interface_InfWinQuestMultiLine'):format(quest[2], getQuestName(quest[1])), "80ee80")
end
end
addLine(_TRANS('INF_Interface_InfWinQuestSource'):format().." WoWHead.com");
end
if (itemInfo.vendors) then
local vendorCount = #itemInfo.vendors
if (vendorCount > 0) then
addLine("")
addLine(_TRANS('INF_Interface_InfWinVendorCount'):format(vendorCount), "ddff40")
for pos, merchant in pairs(itemInfo.vendors) do
addLine("-".._TRANS('INF_Interface_InfWinVendorName'):format(merchant), "dede3c")
if itemInfo.vendorLoc[merchant] then
addLine(" ".._TRANS('INF_Interface_InfWinVendorName'):format(itemInfo.vendorLoc[merchant]), "ffff86")
end
end
end
end
InformantFrame:Show()
else
clear()
addLine(_TRANS('INF_Interface_InfWinNoItem'), "ff4010")
InformantFrame:Show()
end
end
function showHideInfo(iType, iId)
if not iType then iType = "curitem" end
iId = tonumber(iId) or 0
local iTypeCur = tostring(InformantFrame.iType)
local iIdCur = tonumber(InformantFrame.iId) or 0
if (InformantFrame:IsVisible() and iType == iTypeCur and iId == iIdCur) then
return InformantFrame:Hide()
elseif (iType == "curitem") then
showItem(Informant.itemInfo)
elseif (iType == "item") then
elseif (iType == "quest") then
end
end
function OnTooltipAddMoney(self, money)
Informant_ScanTooltip.scanningMoneyFound = money
end
local function TooltipScanBagItem(bag, slot)
local tt = Informant_ScanTooltip
tt.scanningMoneyFound = false
tt:ClearLines()
local _, count = GetContainerItemInfo(bag, slot)
if (not count or count < 1) then return end
tt.scanningStack = count
-- magic happens here as OnTooltipAddMoney gets called
local _, repairCost = tt:SetBagItem(bag, slot)
if (type(repairCost) == "number" and repairCost > 0) then
-- don't count price for items that need repair
tt.scanningMoneyFound = false
return
end
end
local function updateSellPricesFromMerchant()
if (not InformantLocalUpdates.items) then InformantLocalUpdates.items = {} end
local tt = Informant_ScanTooltip
for bag = 0, NUM_BAG_FRAMES do
for slot = 1, GetContainerNumSlots(bag) do
local scanningLink = GetContainerItemLink(bag, slot)
if (scanningLink) then
TooltipScanBagItem(bag, slot)
if (tt.scanningMoneyFound) then
local itemid = idFromLink(scanningLink)
local informantItemInfo = getItem( itemid )
if (informantItemInfo) then
local sellPrice = tt.scanningMoneyFound / tt.scanningStack
if (informantItemInfo.sell ~= sellPrice) then
-- is this item sell price correct in our database? or missing from our database?
local itemName, itemLink, itemQuality, itemLevel, itemUseLevel, itemType, itemSubType, itemStackSize, itemEquipLoc, itemTexture = GetItemInfo(scanningLink)
local newItemInfo = InformantLocalUpdates.items[ itemid ]
if (not newItemInfo) then newItemInfo = {} end
newItemInfo.sell = sellPrice
newItemInfo.stack = itemStackSize
newItemInfo.quantity = itemStackSize
InformantLocalUpdates.items[ itemid ] = newItemInfo
end
end
end -- if money found
end -- if link
end -- for slot
end -- for bag
end
local function updateBuyPricesFromMerchant( vendorID )
if (not InformantLocalUpdates.items) then InformantLocalUpdates.items = {} end
for index = 1, GetMerchantNumItems() do
local link = GetMerchantItemLink(index)
if (link) then
local itemid = idFromLink( link )
local name, texture, price, quantity, numAvailable, isUsableFlag, extendedCostFlag = GetMerchantItemInfo(index)
if (extendedCostFlag) then
--local honorPoints, arenaPoints, itemCount = GetMerchantItemCostInfo(index);
-- NOTE - currently not using this information
end
local informantItemInfo = getItem( itemid )
if (informantItemInfo) then -- this should always be true
if (price ~= informantItemInfo.buy) then
-- is this item buy price correct in our database? or missing from our database?
local itemName, itemLink, itemQuality, itemLevel, itemUseLevel, itemType, itemSubType, itemStackSize, itemEquipLoc, itemTexture = GetItemInfo(link)
-- ccox - currently this will hit often, because we don't take reputation discounts into account for buy pricing
-- should we try to get rep discounts, or just update the price as seen? Then they'll be wrong for alts!
-- could we account for the rep discounts and calculate a baseline?
local newItemInfo = InformantLocalUpdates.items[ itemid ]
if (not newItemInfo) then newItemInfo = {} end
newItemInfo.buy = price
newItemInfo.stack = itemStackSize
newItemInfo.quantity = quantity
InformantLocalUpdates.items[ itemid ] = newItemInfo
end
local foundMerchant = false
if (informantItemInfo.merchantList) then
-- some vendors are known for this item, check the list and see if this vendor is on it
for pos, merchID in pairs(informantItemInfo.merchantList) do
merchID = tonumber(merchID)
if (merchID == vendorID) then
foundMerchant = true
break
end
end
end
-- if no vendors are known, or this vendor isn't on the list, add this vendor
if (not foundMerchant) then
local newItemInfo = InformantLocalUpdates.items[ itemid ]
if (not newItemInfo) then newItemInfo = {} end
local oldList = newItemInfo.merchants
if (oldList) then
local moreMerch = split(oldList, ",")
for pos, merchID in pairs(moreMerch) do
if (tonumber(merchID) == vendorID) then
foundMerchant = true
break
end
end
end
if (not foundMerchant) then
if (oldList) then
newItemInfo.merchants = oldList..","..tostring( vendorID )
else
newItemInfo.merchants = tostring( vendorID )
end
InformantLocalUpdates.items[ itemid ] = newItemInfo
end
end
end -- if info
end -- if link
end -- for GetMerchantNumItems
end
local function updateMerchantName()
if (not InformantLocalUpdates.vendor) then InformantLocalUpdates.vendor = {} end
local vendorName = UnitName("NPC")
local vendorFaction = UnitFactionGroup("NPC")
if (vendorFaction ~= UnitFactionGroup("player")) then
vendorFaction = "Neutral"
end
-- TODO - we are not currently using the faction information for vendors
local vendorGUID = UnitGUID("NPC")
local vendorID = tonumber(strsub(vendorGUID,6,12),16)
if (not self.vendors[ vendorID ] and not InformantLocalUpdates.vendor[ vendorID ]) then
-- add the new vendor name to our update list
local vendorInfo = {}
vendorInfo.name = vendorName;
vendorInfo.faction = vendorFaction;
InformantLocalUpdates.vendor[ vendorID ] = vendorInfo
end
return vendorID
end
local function doUpdateMerchant()
if (not InformantLocalUpdates) then InformantLocalUpdates = {} end
if ((not MerchantFrame:IsVisible()) or InRepairMode()) then return end
if (not Informant.Settings.GetSetting('auto-update')) then return end
local vendorID = updateMerchantName()
updateBuyPricesFromMerchant( vendorID )
updateSellPricesFromMerchant()
wipe(cache)
end
-- cleanup data errors
-- INF-77 - duplicate merchant IDs crept in, blowing the length of the string
local function scrubLocalUpdateInfo()
if (InformantLocalUpdates and InformantLocalUpdates.items
and not InformantLocalUpdates.scrubbedForDupeMerchants) then
for itemID, itemInfo in pairs(InformantLocalUpdates.items) do
if (itemInfo.merchants) then
-- make sure vendor IDs are unique by regenerating the list into a table
local newTable = {}
local merchList = split(itemInfo.merchants, ",")
for pos, merchID in pairs(merchList) do
newTable[ tonumber( merchID ) ] = true
end
-- then converting that table back into our string format
local first = true
local newList
for merchID, _ in pairs(newTable) do
if (first) then
newList = tostring( merchID )
else
newList = newList..","..tostring( merchID )
end
first = false
end
-- finally, replace the existing info with scrubbed info
itemInfo.merchants = newList
InformantLocalUpdates.items[ itemID ] = itemInfo
end
end
InformantLocalUpdates.scrubbedForDupeMerchants = true; -- we should only do this once
end
end
function onQuit()
if (not InformantConfig.position) then
InformantConfig.position = { }
end
InformantConfig.position.x, InformantConfig.position.y = InformantFrame:GetCenter()
end
local function slidebarclickhandler(_, button)
--if we rightclick open the configuration window for the whole addon
Informant.Settings.MakeGuiConfig()
local gui = Informant.Settings.Gui
if (gui:IsVisible()) then
gui:Hide()
else
gui:Show()
end
end
local function slidebar()
if LibStub then
local LibDataBroker = LibStub:GetLibrary("LibDataBroker-1.1", true)
if LibDataBroker then
local LDBButton = LibDataBroker:NewDataObject("Informant", {
type = "launcher",
icon = "Interface\\AddOns\\Informant\\inficon",
OnClick = function(self, button) slidebarclickhandler(self, button) end,
})
function LDBButton:OnTooltipShow()
self:AddLine("Informant Configuration", 1,1,0.5, 1)
end
function LDBButton:OnEnter()
GameTooltip:SetOwner(self, "ANCHOR_NONE")
GameTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT")
GameTooltip:ClearLines()
LDBButton.OnTooltipShow(GameTooltip)
GameTooltip:Show()
end
function LDBButton:OnLeave()
GameTooltip:Hide()
end
end
end
end
function onLoad()
InformantFrame:RegisterEvent("ADDON_LOADED")
Informant_ScanTooltip:SetScript("OnTooltipAddMoney", OnTooltipAddMoney);
InformantFrame:RegisterEvent("MERCHANT_SHOW");
InformantFrame:RegisterEvent("MERCHANT_UPDATE");
Informant_ScanTooltip:SetScript("OnTooltipAddMoney", OnTooltipAddMoney);
InformantFrame:RegisterEvent("MERCHANT_SHOW");
InformantFrame:RegisterEvent("MERCHANT_UPDATE");
InformantFrameTitle:SetText(_TRANS('INF_Interface_InfWinTitle'))
slidebar()
end
local function frameLoaded()
Stubby.RegisterEventHook("PLAYER_LEAVING_WORLD", "Informant", onQuit)
tooltip:Activate()
tooltip:AddCallback(Informant.TooltipHandler, 300)
onLoad()
-- Setup the default for stubby to always load (people can override this on a
-- per toon basis)
Stubby.SetConfig("Informant", "LoadType", "always", true)
-- Register our temporary command hook with stubby
Stubby.RegisterBootCode("Informant", "CommandHandler",
-- Localize Me!
[[
local function cmdHandler(msg)
local cmd, param = msg:lower():match("^(%w+)%s*(.*)$")
cmd = cmd or msg:lower() or "";
param = param or "";
if (cmd == "load") then
if (param == "") then
Stubby.Print("Manually loading Informant...")
LoadAddOn("Informant")
elseif (param == "always") then
Stubby.Print("Setting Informant to always load for this character")
Stubby.SetConfig("Informant", "LoadType", param)
LoadAddOn("Informant")
elseif (param == "never") then
Stubby.Print("Setting Informant to never load automatically for this character (you may still load manually)")
Stubby.SetConfig("Informant", "LoadType", param)
else
Stubby.Print("Your command was not understood")
end
else
Stubby.Print("Informant is currently not loaded.")
Stubby.Print(" You may load it now by typing |cffffffff/informant load|r")
Stubby.Print(" You may also set your loading preferences for this character by using the following commands:")
Stubby.Print(" |cffffffff/informant load always|r - Informant will always load for this character")
Stubby.Print(" |cffffffff/informant load never|r - Informant will never load automatically for this character (you may still load it manually)")
end
end
SLASH_INFORMANT1 = "/informant"
SLASH_INFORMANT2 = "/inform"
SLASH_INFORMANT3 = "/info"
SLASH_INFORMANT4 = "/inf"
SlashCmdList["INFORMANT"] = cmdHandler
]]);
Stubby.RegisterBootCode("Informant", "Triggers", [[
local loadType = Stubby.GetConfig("Informant", "LoadType")
if (loadType == "always") then
LoadAddOn("Informant")
else
Stubby.Print("]].._TRANS('INF_Help_CmdLoadMsg')..[[");
end
]]);
end
function onVariablesLoaded()
if (not InformantConfig) then
InformantConfig = {}
end
InformantFrameTitle:SetText(_TRANS('INF_Interface_InfWinTitle'))
if (InformantConfig.position) then
InformantFrame:ClearAllPoints()
InformantFrame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", InformantConfig.position.x, InformantConfig.position.y)
end
if (not InformantConfig.welcomed) then
clear()
addLine(_TRANS('INF_Help_FirstUse'))
InformantConfig.welcomed = true
end
Informant.InitCommands()
end
function onEvent(event, addon)
if (event == "ADDON_LOADED" and addon:lower() == "informant") then
onVariablesLoaded()
InformantFrame:UnregisterEvent("ADDON_LOADED")
scrubLocalUpdateInfo() -- to fix up data errors
end
if( event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" ) then
doUpdateMerchant()
end
end
function frameActive(isActive)
if (isActive) then
scrollUpdate(0)
end
end
function getRowCount()
return #lines
end
function scrollUpdate()
local numLines = getRowCount()
local offset = 0
if (numLines > 25) then
offset = FauxScrollFrame_GetOffset(InformantFrameScrollBar)
end
local line
for i=1, 25 do
line = lines[i+offset]
local f = _G[format("InformantFrameText%d",i)]
if (line) then
f:SetText(line)
f:Show()
else
f:Hide()
end
end
if (numLines > 25) then
FauxScrollFrame_Update(InformantFrameScrollBar, numLines, 25, numLines)
InformantFrameScrollBar:Show()
else
InformantFrameScrollBar:Hide()
end
end
local function testWrap(text)
InformantFrameTextTest:SetText(text)
if (InformantFrameTextTest:GetWidth() < InformantFrame:GetWidth() - 20) then
return text, ""
end
local pos, test, best, rest
best = text
rest = nil
pos = text:find("%s")
while (pos) do
test = text:sub(1, pos-1)
InformantFrameTextTest:SetText(test)
if (InformantFrameTextTest:GetWidth() < InformantFrame:GetWidth() - 20) or (not rest) then
best = test
rest = test:sub(pos+1)
else
break
end
pos = text:find("%s", pos+1)
end
return best, rest
end
function addLine(text, color, level)
if (not text) then return end
if (not level) then level = 1 end
if (level > 100) then
return
end
if (type(text) == "table") then
for pos, line in pairs(text) do
addLine(line, color, level)
end
return
end
if (not text) then
tinsert(lines, "nil")
else
local best, rest = testWrap(text)
if (color) then
tinsert(lines, ("|cff%s%s|r"):format(color, best))
else
tinsert(lines, best)
end
if (rest) and (rest ~= "") then
addLine(rest, color, level+1)
end
end
scrollUpdate()
end
function clear()
lines = {}
scrollUpdate()
end
-- GLOBAL OBJECT
local DebugLib = LibStub("DebugLib")
local debug, assert, printquick
if DebugLib then
debug, assert, printquick = DebugLib("Informant")
else
function debug() end
assert = debug
printquick = debug
end
-------------------------------------------------------------------------------
-- Prints the specified message to nLog.
--
-- syntax:
-- errorCode, message = infDebugPrint([message][, category][, title][, errorCode][, level])
--
-- parameters:
-- message - (string) the error message
-- nil, no error message specified
-- category - (string) the category of the debug message
-- nil, no category specified
-- title - (string) the title for the debug message
-- nil, no title specified
-- errorCode - (number) the error code
-- nil, no error code specified
-- level - (string) nLog message level
-- Any nLog.levels string is valid.
-- nil, no level specified
--
-- returns:
-- errorCode - (number) errorCode, if one is specified
-- nil, otherwise
-- message - (string) message, if one is specified
-- nil, otherwise
-------------------------------------------------------------------------------
function infDebugPrint(message, category, title, errorCode, level)
return debug(addonName, message, category, title, errorCode, level)
end
-------------------------------------------------------------------------------
-- Prints the specified message to nLog.
--
-- syntax:
-- errorCode, message = debugPrint([message][, title][, errorCode][, level])
--
-- parameters:
-- message - (string) the error message
-- nil, no error message specified
-- title - (string) the title for the debug message
-- nil, no title specified
-- errorCode - (number) the error code
-- nil, no error code specified
-- level - (string) nLog message level
-- Any nLog.levels string is valid.
-- nil, no level specified
--
-- returns:
-- errorCode - (number) errorCode, if one is specified
-- nil, otherwise
-- message - (string) message, if one is specified
-- nil, otherwise
-------------------------------------------------------------------------------
function debugPrint(message, title, errorCode, level)
return Informant.DebugPrint(message, "InfMain", title, errorCode, level)
end
function Dump(...)
return debug:Dump(...)
end
function debugPrintQuick(...)
return printquick(...)
end
Informant = {
version = INFORMANT_VERSION,
GetItem = getItem,
GetRowCount = getRowCount,
AddLine = addLine,
Clear = clear,
ShowHideInfo = showHideInfo,
getItemVendorInfo = getInformantVendorInfo,
-- These functions are only meant for internal use.
SetSkills = setSkills,
SetRequirements = setRequirements,
SetVendors = setVendors,
SetDatabase = setDatabase,
SetQuestStarts = setQuestStarts,
SetQuestRewards = setQuestRewards,
SetQuestRequires = setQuestRequires,
SetQuestNames = setQuestNames,
SetVendorLocation = setVendorLocation,
SetZones = setZones,
SetCrafted = setCrafted,
SetCraftCount = setCraftCount,
FrameActive = frameActive,
FrameLoaded = frameLoaded,
ScrollUpdate = scrollUpdate,
GetLocale = getLocale,
GetQuestName = getQuestName,
OnEvent = onEvent,
DebugPrint = infDebugPrint,
DebugPrintQuick = debugPrintQuick
}
_G.Informant = Informant