init
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
## Interface: 30300
|
||||
## Title: Bagnon Forever
|
||||
## Notes: Stores inventory information about your characters
|
||||
## Notes-zhTW: 儲存角色背包和銀行的物品資訊
|
||||
## Notes-zhCN: 保存角色背包与银行内物品的信息
|
||||
## Author: Tuller
|
||||
## Version: 1.1.2
|
||||
## SavedVariables: BagnonForeverDB
|
||||
## LoadOnDemand: 0
|
||||
db.lua
|
||||
ui.xml
|
||||
@@ -0,0 +1,454 @@
|
||||
--[[
|
||||
Database.lua
|
||||
BagnonForever's implementation of BagnonDB
|
||||
--]]
|
||||
|
||||
BagnonDB = CreateFrame('GameTooltip', 'BagnonDB', nil, 'GameTooltipTemplate')
|
||||
BagnonDB:SetScript('OnEvent', function(self, event, arg1)
|
||||
if arg1 == 'Bagnon_Forever' then
|
||||
self:UnregisterEvent('ADDON_LOADED')
|
||||
self:Initialize()
|
||||
end
|
||||
end)
|
||||
BagnonDB:RegisterEvent('ADDON_LOADED')
|
||||
|
||||
--constants
|
||||
local L = BAGNON_FOREVER_LOCALS
|
||||
local CURRENT_VERSION = GetAddOnMetadata('Bagnon_Forever', 'Version')
|
||||
local NUM_EQUIPMENT_SLOTS = 19
|
||||
|
||||
--locals
|
||||
local currentPlayer = UnitName('player') --the name of the current player that's logged on
|
||||
local currentRealm = GetRealmName() --what currentRealm we're on
|
||||
local playerList --a sorted list of players
|
||||
|
||||
|
||||
--[[ Local Functions ]]--
|
||||
|
||||
local function ToIndex(bag, slot)
|
||||
if tonumber(bag) then
|
||||
return (bag < 0 and bag*100 - slot) or bag*100 + slot
|
||||
end
|
||||
return bag .. slot
|
||||
end
|
||||
|
||||
local function ToBagIndex(bag)
|
||||
return (tonumber(bag) and bag*100) or bag
|
||||
end
|
||||
|
||||
--returns the full item link only for items that have enchants/suffixes, otherwise returns the item's ID
|
||||
local function ToShortLink(link)
|
||||
if link then
|
||||
local a,b,c,d,e,f,g,h = link:match('(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+)')
|
||||
if(b == '0' and b == c and c == d and d == e and e == f and f == g) then
|
||||
return a
|
||||
end
|
||||
return format('item:%s:%s:%s:%s:%s:%s:%s:%s', a, b, c, d, e, f, g, h)
|
||||
end
|
||||
end
|
||||
|
||||
local function GetBagSize(bag)
|
||||
if bag == KEYRING_CONTAINER then
|
||||
return GetKeyRingSize()
|
||||
end
|
||||
if bag == 'e' then
|
||||
return NUM_EQUIPMENT_SLOTS
|
||||
end
|
||||
return GetContainerNumSlots(bag)
|
||||
end
|
||||
|
||||
|
||||
--[[ Addon Loading ]]--
|
||||
|
||||
function BagnonDB:Initialize()
|
||||
self:LoadSettings()
|
||||
|
||||
self:SetScript('OnEvent', function(self, event, ...)
|
||||
if self[event] then
|
||||
self[event](self, event, ...)
|
||||
end
|
||||
end)
|
||||
|
||||
if IsLoggedIn() then
|
||||
self:PLAYER_LOGIN()
|
||||
else
|
||||
self:RegisterEvent('PLAYER_LOGIN')
|
||||
end
|
||||
end
|
||||
|
||||
function BagnonDB:LoadSettings()
|
||||
if not(BagnonForeverDB and BagnonForeverDB.version) then
|
||||
BagnonForeverDB = {version = CURRENT_VERSION}
|
||||
else
|
||||
local cMajor, cMinor = CURRENT_VERSION:match('(%d+)%.(%d+)')
|
||||
local major, minor = BagnonForeverDB.version:match('(%d+)%.(%d+)')
|
||||
|
||||
if major ~= cMajor then
|
||||
BagnonForeverDB = {version = cVersion}
|
||||
elseif minor ~= cMinor then
|
||||
self:UpdateSettings()
|
||||
end
|
||||
|
||||
if BagnonForeverDB.version ~= CURRENT_VERSION then
|
||||
self:UpdateVersion()
|
||||
end
|
||||
end
|
||||
|
||||
self.db = BagnonForeverDB
|
||||
if not self.db[currentRealm] then
|
||||
self.db[currentRealm] = {}
|
||||
end
|
||||
self.rdb = self.db[currentRealm]
|
||||
|
||||
if not self.rdb[currentPlayer] then
|
||||
self.rdb[currentPlayer] = {}
|
||||
end
|
||||
self.pdb = self.rdb[currentPlayer]
|
||||
end
|
||||
|
||||
function BagnonDB:UpdateSettings()
|
||||
end
|
||||
|
||||
function BagnonDB:UpdateVersion()
|
||||
BagnonForeverDB.version = CURRENT_VERSION
|
||||
print(format('BagnonForever: Updated to v%s', BagnonForeverDB.version))
|
||||
end
|
||||
|
||||
|
||||
--[[ Events ]]--
|
||||
|
||||
function BagnonDB:PLAYER_LOGIN()
|
||||
self:SaveMoney()
|
||||
self:UpdateBag(BACKPACK_CONTAINER)
|
||||
self:UpdateBag(KEYRING_CONTAINER)
|
||||
self:SaveEquipment()
|
||||
self:SaveNumBankSlots()
|
||||
|
||||
self:RegisterEvent('BANKFRAME_OPENED')
|
||||
self:RegisterEvent('BANKFRAME_CLOSED')
|
||||
self:RegisterEvent('PLAYER_MONEY')
|
||||
self:RegisterEvent('BAG_UPDATE')
|
||||
self:RegisterEvent('PLAYERBANKSLOTS_CHANGED')
|
||||
self:RegisterEvent('UNIT_INVENTORY_CHANGED')
|
||||
self:RegisterEvent('PLAYERBANKBAGSLOTS_CHANGED')
|
||||
end
|
||||
|
||||
function BagnonDB:PLAYER_MONEY()
|
||||
self:SaveMoney()
|
||||
end
|
||||
|
||||
function BagnonDB:BAG_UPDATE(event, bag)
|
||||
if not(bag == BANK_CONTAINER or bag > NUM_BAG_SLOTS) or self.atBank then
|
||||
self:OnBagUpdate(bag)
|
||||
end
|
||||
end
|
||||
|
||||
function BagnonDB:PLAYERBANKSLOTS_CHANGED()
|
||||
self:UpdateBag(BANK_CONTAINER)
|
||||
end
|
||||
|
||||
function BagnonDB:PLAYERBANKBAGSLOTS_CHANGED()
|
||||
self:SaveNumBankSlots()
|
||||
end
|
||||
|
||||
function BagnonDB:BANKFRAME_OPENED()
|
||||
self.atBank = true
|
||||
|
||||
self:UpdateBag(BANK_CONTAINER)
|
||||
for i = 1, GetNumBankSlots() do
|
||||
self:UpdateBag(i + 4)
|
||||
end
|
||||
end
|
||||
|
||||
function BagnonDB:BANKFRAME_CLOSED()
|
||||
self.atBank = nil
|
||||
end
|
||||
|
||||
function BagnonDB:UNIT_INVENTORY_CHANGED(event, unit)
|
||||
if unit == 'player' then
|
||||
self:SaveEquipment()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Access Functions
|
||||
Bagnon requires all of these functions to be present when attempting to view cached data
|
||||
--]]
|
||||
|
||||
--[[
|
||||
BagnonDB:GetPlayerList()
|
||||
returns:
|
||||
iterator of all players on this realm with data
|
||||
usage:
|
||||
for playerName, data in BagnonDB:GetPlayers()
|
||||
--]]
|
||||
function BagnonDB:GetPlayerList()
|
||||
if(not playerList) then
|
||||
playerList = {}
|
||||
|
||||
for player in self:GetPlayers() do
|
||||
table.insert(playerList, player)
|
||||
end
|
||||
|
||||
--sort by currentPlayer first, then alphabetically
|
||||
table.sort(playerList, function(a, b)
|
||||
if(a == currentPlayer) then
|
||||
return true
|
||||
elseif(b == currentPlayer) then
|
||||
return false
|
||||
end
|
||||
return a < b
|
||||
end)
|
||||
end
|
||||
return playerList
|
||||
end
|
||||
|
||||
function BagnonDB:GetPlayers()
|
||||
return pairs(self.rdb)
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
BagnonDB:GetMoney(player)
|
||||
args:
|
||||
player (string)
|
||||
the name of the player we're looking at. This is specific to the current realm we're on
|
||||
|
||||
returns:
|
||||
(number) How much money, in copper, the given player has
|
||||
--]]
|
||||
function BagnonDB:GetMoney(player)
|
||||
local playerData = self.rdb[player]
|
||||
if playerData then
|
||||
return playerData.g or 0
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[
|
||||
BagnonDB:GetNumBankSlots(player)
|
||||
args:
|
||||
player (string)
|
||||
the name of the player we're looking at. This is specific to the current realm we're on
|
||||
|
||||
returns:
|
||||
(number or nil) How many bank slots the current player has purchased
|
||||
--]]
|
||||
function BagnonDB:GetNumBankSlots(player)
|
||||
local playerData = self.rdb[player]
|
||||
if playerData then
|
||||
return playerData.numBankSlots
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
BagnonDB:GetBagData(bag, player)
|
||||
args:
|
||||
player (string)
|
||||
the name of the player we're looking at. This is specific to the current realm we're on
|
||||
bag (number)
|
||||
the number of the bag we're looking at.
|
||||
|
||||
returns:
|
||||
size (number)
|
||||
How many items the bag can hold (number)
|
||||
hyperlink (string)
|
||||
The hyperlink of the bag
|
||||
count (number)
|
||||
How many items are in the bag. This is used by ammo and soul shard bags
|
||||
--]]
|
||||
function BagnonDB:GetBagData(bag, player)
|
||||
local playerDB = self.rdb[player]
|
||||
if playerDB then
|
||||
local bagInfo = playerDB[ToBagIndex(bag)]
|
||||
if bagInfo then
|
||||
local size, link, count = strsplit(',', bagInfo)
|
||||
local hyperLink = (link and select(2, GetItemInfo(link))) or nil
|
||||
return tonumber(size), hyperLink, tonumber(count) or 1, GetItemIcon(link)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
BagnonDB:GetItemData(bag, slot, player)
|
||||
args:
|
||||
player (string)
|
||||
the name of the player we're looking at. This is specific to the current realm we're on
|
||||
bag (number)
|
||||
the number of the bag we're looking at.
|
||||
itemSlot (number)
|
||||
the specific item slot we're looking at
|
||||
|
||||
returns:
|
||||
hyperLink (string)
|
||||
The hyperLink of the item
|
||||
count (number)
|
||||
How many of there are of the specific item
|
||||
texture (string)
|
||||
The filepath of the item's texture
|
||||
quality (number)
|
||||
The numeric representaiton of the item's quality: from 0 (poor) to 7 (artifcat)
|
||||
--]]
|
||||
function BagnonDB:GetItemData(bag, slot, player)
|
||||
local playerDB = self.rdb[player]
|
||||
if playerDB then
|
||||
local itemInfo = playerDB[ToIndex(bag, slot)]
|
||||
if itemInfo then
|
||||
local link, count = strsplit(',', itemInfo)
|
||||
if link then
|
||||
local hyperLink, quality = select(2, GetItemInfo(link))
|
||||
return hyperLink, tonumber(count) or 1, GetItemIcon(link), tonumber(quality)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Returns how many of the specific item id the given player has in the given bag
|
||||
--]]
|
||||
function BagnonDB:GetItemCount(itemLink, bag, player)
|
||||
local total = 0
|
||||
local itemLink = select(2, GetItemInfo(ToShortLink(itemLink)))
|
||||
local size = (self:GetBagData(bag, player)) or 0
|
||||
for slot = 1, size do
|
||||
local link, count = self:GetItemData(bag, slot, player)
|
||||
if link == itemLink then
|
||||
total = total + (count or 1)
|
||||
end
|
||||
end
|
||||
|
||||
return total
|
||||
end
|
||||
|
||||
--[[
|
||||
Storage Functions
|
||||
How we store the data (duh)
|
||||
--]]
|
||||
|
||||
|
||||
--[[ Storage Functions ]]--
|
||||
|
||||
function BagnonDB:SaveMoney()
|
||||
self.pdb.g = GetMoney()
|
||||
end
|
||||
|
||||
function BagnonDB:SaveNumBankSlots()
|
||||
self.pdb.numBankSlots = GetNumBankSlots()
|
||||
end
|
||||
|
||||
--saves all the player's equipment data information
|
||||
function BagnonDB:SaveEquipment()
|
||||
for slot = 0, NUM_EQUIPMENT_SLOTS do
|
||||
local link = GetInventoryItemLink('player', slot)
|
||||
local index = ToIndex('e', slot)
|
||||
|
||||
if link then
|
||||
local link = ToShortLink(link)
|
||||
local count = GetInventoryItemCount('player', slot)
|
||||
count = count > 1 and count or nil
|
||||
|
||||
if(link and count) then
|
||||
self.pdb[index] = format('%s,%d', link, count)
|
||||
else
|
||||
self.pdb[index] = link
|
||||
end
|
||||
else
|
||||
self.pdb[index] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--saves data about a specific item the current player has
|
||||
function BagnonDB:SaveItem(bag, slot)
|
||||
local texture, count = GetContainerItemInfo(bag, slot)
|
||||
|
||||
local index = ToIndex(bag, slot)
|
||||
|
||||
if texture then
|
||||
local link = ToShortLink(GetContainerItemLink(bag, slot))
|
||||
count = count > 1 and count or nil
|
||||
|
||||
if(link and count) then
|
||||
self.pdb[index] = format('%s,%d', link, count)
|
||||
else
|
||||
self.pdb[index] = link
|
||||
end
|
||||
else
|
||||
self.pdb[index] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--saves all information about the given bag, EXCEPT the bag's contents
|
||||
function BagnonDB:SaveBag(bag)
|
||||
local data = self.pdb
|
||||
local size = GetBagSize(bag)
|
||||
local index = ToBagIndex(bag)
|
||||
|
||||
if size > 0 then
|
||||
local equipSlot = bag > 0 and ContainerIDToInventoryID(bag)
|
||||
local link = ToShortLink(GetInventoryItemLink('player', equipSlot))
|
||||
local count = GetInventoryItemCount('player', equipSlot)
|
||||
if count < 1 then
|
||||
count = nil
|
||||
end
|
||||
|
||||
if(size and link and count) then
|
||||
self.pdb[index] = format('%d,%s,%d', size, link, count)
|
||||
elseif(size and link) then
|
||||
self.pdb[index] = format('%d,%s', size, link)
|
||||
else
|
||||
self.pdb[index] = size
|
||||
end
|
||||
else
|
||||
self.pdb[index] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--saves both relevant information about the given bag, and all information about items in the given bag
|
||||
function BagnonDB:UpdateBag(bag)
|
||||
self:SaveBag(bag)
|
||||
for slot = 1, GetBagSize(bag) do
|
||||
self:SaveItem(bag, slot)
|
||||
end
|
||||
end
|
||||
|
||||
function BagnonDB:OnBagUpdate(bag)
|
||||
if self.atBank then
|
||||
for i = 1, (NUM_BAG_SLOTS + GetNumBankSlots()) do
|
||||
self:SaveBag(i)
|
||||
end
|
||||
else
|
||||
for i = 1, NUM_BAG_SLOTS do
|
||||
self:SaveBag(i)
|
||||
end
|
||||
end
|
||||
|
||||
for slot = 1, GetBagSize(bag) do
|
||||
self:SaveItem(bag, slot)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--[[ Removal Functions ]]--
|
||||
|
||||
--removes all saved data about the given player
|
||||
function BagnonDB:RemovePlayer(player, realm)
|
||||
local realm = realm or currentRealm
|
||||
local rdb = self.db[realm]
|
||||
if rdb then
|
||||
rdb[player] = nil
|
||||
end
|
||||
|
||||
if realm == currentRealm and playerList then
|
||||
for i,character in pairs(playerList) do
|
||||
if(character == player) then
|
||||
table.remove(playerList, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,97 @@
|
||||
--[[
|
||||
BagnonDBUI
|
||||
Functions for the dropdown menu for showing cached data
|
||||
No alterations if this code should be needed to make it work with other databases
|
||||
|
||||
Essentially the dropdown is used to switch between the inventory of other characters
|
||||
Why not use a normal dropdown? It takes a lot of memory
|
||||
--]]
|
||||
|
||||
local currentFrame
|
||||
local dropdown
|
||||
local info = {}
|
||||
|
||||
--adds a checkable item to a dropdown menu
|
||||
local function AddCheckItem(text, value, func, checked, hasArrow, level, arg1, arg2)
|
||||
info.text = text
|
||||
info.func = func
|
||||
info.value = value
|
||||
info.hasArrow = (hasArrow and true) or nil
|
||||
info.notCheckable = false
|
||||
info.checked = checked
|
||||
info.arg1 = arg1
|
||||
info.arg2 = arg2
|
||||
UIDropDownMenu_AddButton(info, level)
|
||||
end
|
||||
|
||||
--adds an uncheckable item to a dropdown menu
|
||||
local function AddItem(text, value, func, level, arg1, arg2)
|
||||
info.text = text
|
||||
info.func = func
|
||||
info.value = value
|
||||
info.hasArrow = false
|
||||
info.notCheckable = true
|
||||
info.checked = false
|
||||
info.arg1 = arg1
|
||||
info.arg2 = arg2
|
||||
UIDropDownMenu_AddButton(info, level)
|
||||
end
|
||||
|
||||
local function CharSelect_OnClick(self, player, delete)
|
||||
local newPlayer
|
||||
if delete then
|
||||
--remove the selected player
|
||||
BagnonDB:RemovePlayer(player)
|
||||
--select the current player
|
||||
newPlayer = UnitName('player')
|
||||
else
|
||||
--select the clicked player
|
||||
newPlayer = player
|
||||
end
|
||||
|
||||
--show the given player, and check the selected one
|
||||
currentFrame:SetPlayer(newPlayer)
|
||||
|
||||
--hide the previous dropdown menus (hack)
|
||||
for i = 1, UIDROPDOWNMENU_MENU_LEVEL-1 do
|
||||
getglobal("DropDownList"..i):Hide()
|
||||
end
|
||||
end
|
||||
|
||||
--populate the list, add a delete button to all characters that aren't the current player
|
||||
local function CharSelect_Initialize(self, level)
|
||||
local playerList = BagnonDB:GetPlayerList()
|
||||
local level = level or 1
|
||||
|
||||
if level == 1 then
|
||||
local selected = currentFrame:GetPlayer()
|
||||
local current = UnitName('player')
|
||||
|
||||
for i,player in ipairs(playerList) do
|
||||
AddCheckItem(player, i, CharSelect_OnClick, player == selected, player ~= current, level, player)
|
||||
end
|
||||
elseif level == 2 then
|
||||
AddItem(REMOVE, nil, CharSelect_OnClick, level, playerList[UIDROPDOWNMENU_MENU_VALUE], true)
|
||||
end
|
||||
end
|
||||
|
||||
local function CharSelect_Create()
|
||||
dropdown = CreateFrame("Frame", "BagnonDBCharSelect", UIParent, "UIDropDownMenuTemplate")
|
||||
dropdown:SetID(1)
|
||||
UIDropDownMenu_Initialize(dropdown, CharSelect_Initialize, "MENU")
|
||||
|
||||
return dropdown
|
||||
end
|
||||
|
||||
|
||||
--[[ Usable Functions ]]--
|
||||
|
||||
--set which frame to "parent" the dropdown to
|
||||
function BagnonDB:SetDropdownFrame(frame)
|
||||
currentFrame = frame
|
||||
end
|
||||
|
||||
--show the character select list at the given location
|
||||
function BagnonDB:ToggleDropdown(anchor, offX, offY)
|
||||
ToggleDropDownMenu(1, nil, dropdown or CharSelect_Create(), anchor, offX, offY)
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
|
||||
<Script file="ui.lua"/>
|
||||
|
||||
<!-- a button added to each frame, shows the character selection list when clicked -->
|
||||
<Button name="BagnonDBUIDropDownButton" topLevel="true" virtual="true">
|
||||
<Size x="24" y="24"/>
|
||||
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
BagnonDB:SetDropdownFrame(self:GetParent())
|
||||
BagnonDB:ToggleDropdown(self, 0, 2)
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
<NormalTexture file="Interface\ChatFrame\UI-ChatIcon-ScrollDown-Up" setAllPoints="true"/>
|
||||
<PushedTexture file="Interface\ChatFrame\UI-ChatIcon-ScrollDown-Down" setAllPoints="true"/>
|
||||
<HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD" setAllPoints="true"/>
|
||||
</Button>
|
||||
</Ui>
|
||||
Reference in New Issue
Block a user