Compare commits
10 commits
c1d9d3f7c6
...
43026d1109
| Author | SHA1 | Date | |
|---|---|---|---|
| 43026d1109 | |||
| cad2e8cc26 | |||
| dfdca08ea9 | |||
| c758a03b52 | |||
| cd66c242c4 | |||
| 88897f3c54 | |||
| 10e8d21191 | |||
|
|
bf6652036b | ||
|
|
4a03ece3d3 | ||
|
|
8a6c8fd3a2 |
21 changed files with 839 additions and 519 deletions
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
* -text
|
||||
75
.gitea/workflows/release.yml
Normal file
75
.gitea/workflows/release.yml
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*-coa.*' # Asc-1.1.6-coa.2, 9.1.40-coa.3, etc.
|
||||
- 'v*' # v0.3.0 for repos without an upstream version
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: linux-amd64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # build_zip uses git archive HEAD; full history is fine
|
||||
|
||||
- name: Build per-addon zip(s)
|
||||
run: bash tools/build_zip.sh
|
||||
|
||||
- name: Publish release (Gitea API direct; no action dependency)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
API: ${{ github.server_url }}/api/v1
|
||||
# Gitea attachment ceiling is 200 MiB (see roles/gitea config).
|
||||
# Skip anything larger so one oversized asset doesn't fail the job.
|
||||
MAX_BYTES: 209715200
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Create the release (or reuse if it already exists for this tag).
|
||||
RID=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$API/repos/$REPO/releases/tags/$TAG" 2>/dev/null \
|
||||
| jq -r '.id // empty')
|
||||
if [ -z "$RID" ]; then
|
||||
RID=$(curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"$API/repos/$REPO/releases" \
|
||||
-d "$(jq -nc --arg t "$TAG" '{tag_name:$t,name:$t,draft:false,prerelease:false,hide_archive_links:true}')" \
|
||||
| jq -r '.id')
|
||||
fi
|
||||
echo "release id: $RID"
|
||||
# Gitea honors hide_archive_links only on edit, not create — PATCH it
|
||||
# so the auto-generated Source Code (zip/tar.gz) links stay hidden.
|
||||
curl -sf -X PATCH -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \
|
||||
"$API/repos/$REPO/releases/$RID" -d '{"hide_archive_links":true}' >/dev/null || true
|
||||
# Upload every dist/*.zip. Per-asset failures don't fail the job —
|
||||
# we want partial releases to still publish rather than block the
|
||||
# whole pipeline on one big file.
|
||||
failed=0
|
||||
uploaded=0
|
||||
for f in dist/*.zip; do
|
||||
name=$(basename "$f")
|
||||
size=$(stat -c '%s' "$f")
|
||||
if [ "$size" -gt "$MAX_BYTES" ]; then
|
||||
echo "::warning::skip $name (${size} B > ${MAX_BYTES} B Gitea limit; host on CDN instead)"
|
||||
failed=$((failed+1))
|
||||
continue
|
||||
fi
|
||||
echo "uploading $name ($(numfmt --to=iec "$size"))"
|
||||
if curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@$f" \
|
||||
"$API/repos/$REPO/releases/$RID/assets?name=$name" \
|
||||
| jq -r '" -> " + .browser_download_url'; then
|
||||
uploaded=$((uploaded+1))
|
||||
else
|
||||
echo "::warning::upload failed for $name"
|
||||
failed=$((failed+1))
|
||||
fi
|
||||
done
|
||||
echo "release published: $uploaded uploaded, $failed skipped/failed"
|
||||
# Only fail the job if NO assets uploaded — a release with zero
|
||||
# attachments isn't useful to anyone.
|
||||
[ "$uploaded" -gt 0 ]
|
||||
77
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
77
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -1,77 +0,0 @@
|
|||
name: "Bug Report"
|
||||
description: Create a report to help us improve this addon
|
||||
labels: '🐛 Bug'
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please search for existing issues before creating a new one.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: What did you expect to happen and what happened instead?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: flavor
|
||||
attributes:
|
||||
label: Realm
|
||||
description: What realm did this occur on?
|
||||
options:
|
||||
- Area 52 (Default)
|
||||
- Seasonal
|
||||
- Grizzly Hills
|
||||
- Rexxar
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: testing
|
||||
attributes:
|
||||
label: Tested with only this addon
|
||||
description: Did you try having just this addon as the only enabled addon and everything else disabled?
|
||||
options:
|
||||
- label: "Yes"
|
||||
- label: "No"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Lua Error
|
||||
description: |
|
||||
Do you have an error log of what happened? If you don't see any errors, make sure that error reporting is enabled (`/console scriptErrors 1`)
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
description: Please list out the steps to reproduce your bug.
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Last Good Version
|
||||
description: |
|
||||
Was it working in a previous version? If yes, which update did it stop working? If you don't know, when was the last date you were aware it was working
|
||||
placeholder: "MM/DD/YYYY"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
placeholder: Click here to attach your screenshots via the editor button in the top right.
|
||||
validations:
|
||||
required: false
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
1
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1 +0,0 @@
|
|||
blank_issues_enabled: false
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
28
.github/PULL_REQUEST_TEPMLATE.md
vendored
28
.github/PULL_REQUEST_TEPMLATE.md
vendored
|
|
@ -1,28 +0,0 @@
|
|||
# Description
|
||||
|
||||
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.
|
||||
<!-- A #issueNumber will be sufficient. -->
|
||||
Fixes #(issue)
|
||||
|
||||
## Type of change
|
||||
|
||||
Please delete options that are not relevant.
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
|
||||
## How Has This Been Tested
|
||||
|
||||
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
|
||||
|
||||
- [ ] Test A
|
||||
- [ ] Test B
|
||||
|
||||
## Checklist
|
||||
<!-- These can be checked off after the pull request is submitted, in case you want discussion before they are completely ready -->
|
||||
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
|
||||
<!-- Is there any additional work that needs to be done? If so, add it to the above list -->
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -4,4 +4,7 @@
|
|||
.install
|
||||
.lua/*
|
||||
.vscode
|
||||
.idea
|
||||
.idea
|
||||
deploy.bat
|
||||
claude.md
|
||||
dist/
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ local defaultColScripts = {
|
|||
end,
|
||||
|
||||
OnDoubleClick = function(self, ...)
|
||||
if self.rt.disabled then return end
|
||||
if self.rt.disabled or IsAltKeyDown() then return end
|
||||
local data = self.row.data
|
||||
if data.expandable then
|
||||
self.rt:ToggleExpanded(data.itemString)
|
||||
|
|
|
|||
|
|
@ -14,9 +14,19 @@ local AceGUI = LibStub("AceGUI-3.0") -- load the AceGUI libraries
|
|||
local lib = TSMAPI
|
||||
|
||||
local bankType
|
||||
local ascensionBankType
|
||||
local fullMoves, splitMoves, bagState = {}, {}, {}
|
||||
local callbackMsg = {}
|
||||
|
||||
local function GetAscensionBankType()
|
||||
if GuildBankFrame and GuildBankFrame.IsPersonalBank then
|
||||
return "personal"
|
||||
elseif GuildBankFrame and GuildBankFrame.IsRealmBank then
|
||||
return "realm"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- this is a set of wrapper functions so that I can switch
|
||||
-- between guildbank and bank function easily (taken from warehousing)
|
||||
|
||||
|
|
@ -42,6 +52,7 @@ function TSM:OnEnable()
|
|||
|
||||
TSM:RegisterEvent("GUILDBANKFRAME_OPENED", function(event)
|
||||
bankType = "guildbank"
|
||||
ascensionBankType = GetAscensionBankType() -- Ascension WoW: detect personal/realm bank
|
||||
end)
|
||||
|
||||
TSM:RegisterEvent("BANKFRAME_OPENED", function(event)
|
||||
|
|
@ -50,6 +61,7 @@ function TSM:OnEnable()
|
|||
|
||||
TSM:RegisterEvent("GUILDBANKFRAME_CLOSED", function(event, addon)
|
||||
bankType = nil
|
||||
ascensionBankType = nil -- Ascension WoW: reset
|
||||
TSM:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED")
|
||||
end)
|
||||
|
||||
|
|
@ -402,13 +414,23 @@ function TSM.generateMoves(includeSoulbound)
|
|||
|
||||
if next(fullMoves) ~= nil then
|
||||
if bankType == "guildbank" then
|
||||
TSMAPI:CreateTimeDelay("moveItem", 0.05, TSM.moveItem, 0.35)
|
||||
-- Ascension WoW: Personal/Realm banks don't need slow delays like real guild banks
|
||||
if ascensionBankType then
|
||||
TSMAPI:CreateTimeDelay("moveItem", 0.05, TSM.moveItem, 0.05)
|
||||
else
|
||||
TSMAPI:CreateTimeDelay("moveItem", 0.05, TSM.moveItem, 0.35)
|
||||
end
|
||||
else
|
||||
TSMAPI:CreateTimeDelay("moveItem", 0.05, TSM.moveItem, 0.05)
|
||||
end
|
||||
elseif next(splitMoves) ~= nil then
|
||||
if bankType == "guildbank" then
|
||||
TSMAPI:CreateTimeDelay("moveSplitItem", 0.05, TSM.moveSplitItem, 0.75)
|
||||
-- Ascension WoW: Personal/Realm banks don't need slow delays like real guild banks
|
||||
if ascensionBankType then
|
||||
TSMAPI:CreateTimeDelay("moveSplitItem", 0.05, TSM.moveSplitItem, 0.1)
|
||||
else
|
||||
TSMAPI:CreateTimeDelay("moveSplitItem", 0.05, TSM.moveSplitItem, 0.75)
|
||||
end
|
||||
else
|
||||
TSMAPI:CreateTimeDelay("moveSplitItem", 0.05, TSM.moveSplitItem, 0.4)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -83,9 +83,9 @@ function Post:GetScanListAndSetup(GUIRef, options)
|
|||
totalToPost, totalPosted, count = 0, 0, 0
|
||||
|
||||
local tempList, scanList = {}, {}
|
||||
|
||||
|
||||
Post:UpdateBagState()
|
||||
|
||||
|
||||
local function HasEnoughToPost(operation, itemString)
|
||||
local maxStackSize = select(8, TSMAPI:GetSafeItemInfo(itemString)) or 1
|
||||
local perAuction = min(maxStackSize, operation.stackSize)
|
||||
|
|
@ -129,7 +129,7 @@ function Post:GetScanListAndSetup(GUIRef, options)
|
|||
tinsert(scanList, itemString)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
TSMAPI:FireEvent("AUCTIONING:POST:START", {numItems=#scanList, isGroup=true})
|
||||
return scanList
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ L["<< Hide Queue"] = true
|
|||
L["<None>"] = true
|
||||
L["AH"] = true
|
||||
L["All"] = true
|
||||
L["Are you sure you want to clear the entire queue?"] = true
|
||||
L["Are you sure you want to reset all material prices to the default value?"] = true
|
||||
L["Ask Later"] = true
|
||||
L["Auction House"] = true
|
||||
|
|
@ -168,6 +169,9 @@ L["Total"] = true
|
|||
L["Vendor"] = true
|
||||
L["Visit Bank"] = true
|
||||
L["Visit Guild Bank"] = true
|
||||
L["Visit Personal Bank"] = true
|
||||
L["Visit Realm Bank"] = true
|
||||
L["Realm Bank"] = true
|
||||
L["Visit Vendor"] = true
|
||||
L["Warning: The min restock quantity must be lower than the max restock quantity."] = true
|
||||
L["When you click on the \"Restock Queue\" button enough of each craft will be queued so that you have this maximum number on hand. For example, if you have 2 of item X on hand and you set this to 4, 2 more will be added to the craft queue."] = true
|
||||
|
|
|
|||
|
|
@ -539,9 +539,13 @@ function GUI:CreateQueueFrame(parent)
|
|||
end
|
||||
|
||||
end
|
||||
-- Position tooltip next to the row, on left or right depending on screen position
|
||||
GameTooltip:SetOwner(self, "ANCHOR_NONE")
|
||||
-- GameTooltip:SetPoint("LEFT", self, "RIGHT")
|
||||
GameTooltip:SetPoint("LEFT", self, "LEFT")
|
||||
if self:GetRight() >= (GetScreenWidth() / 2) then
|
||||
GameTooltip:SetPoint("TOPRIGHT", self, "TOPLEFT", -5, 0)
|
||||
else
|
||||
GameTooltip:SetPoint("TOPLEFT", self, "TOPRIGHT", 5, 0)
|
||||
end
|
||||
GameTooltip:AddLine(TSM.db.realm.crafts[data.spellID].name .. " (x" .. data.numQueued .. ")")
|
||||
|
||||
local cost = TSM.Cost:GetCraftPrices(data.spellID)
|
||||
|
|
@ -621,6 +625,8 @@ function GUI:CreateQueueFrame(parent)
|
|||
name = color .. inventory .. "/" .. need .. "|r " .. name
|
||||
GameTooltip:AddLine(name, 1, 1, 1)
|
||||
end
|
||||
GameTooltip:AddLine(" ")
|
||||
GameTooltip:AddLine("|cff00ff00Ctrl+Click|r to remove from queue", 0.7, 0.7, 0.7)
|
||||
GameTooltip:Show()
|
||||
end
|
||||
|
||||
|
|
@ -644,6 +650,13 @@ function GUI:CreateQueueFrame(parent)
|
|||
TSM.db.realm.queueStatus.collapsed[data.profession] = not TSM.db.realm.queueStatus.collapsed[data.profession]
|
||||
end
|
||||
GUI:UpdateQueue()
|
||||
elseif data.spellID and IsControlKeyDown() then
|
||||
-- Ctrl+Left-Click: Remove item from queue
|
||||
local craft = TSM.db.realm.crafts[data.spellID]
|
||||
if craft then
|
||||
craft.queued = 0
|
||||
GUI:UpdateQueue()
|
||||
end
|
||||
elseif data.index then
|
||||
GUI:CastTradeSkill(data.index, min(data.canCraft, data.numQueued), data.velName)
|
||||
end
|
||||
|
|
@ -739,20 +752,31 @@ function GUI:CreateQueueFrame(parent)
|
|||
btn:SetHeight(20)
|
||||
btn:SetText(L["Clear Queue"])
|
||||
btn:SetScript("OnClick", function()
|
||||
TSM.Queue:ClearQueue()
|
||||
GUI:UpdateQueue()
|
||||
if GUI.frame.gather:IsVisible() then
|
||||
GUI.frame.gather:Hide()
|
||||
end
|
||||
private.gather = {}
|
||||
GUI:UpdateGatherSelectionWindow()
|
||||
if GUI.gatheringFrame:IsShown() then
|
||||
GUI.gatheringFrame:Hide()
|
||||
TSM.db.realm.gathering.crafter = nil
|
||||
TSM.db.realm.gathering.neededMats = {}
|
||||
TSM.db.realm.gathering.gatheredMats = false
|
||||
TSM.db.realm.sourceStatus.collapsed = {}
|
||||
end
|
||||
StaticPopupDialogs["TSM_CRAFTING_CLEAR_QUEUE"] = StaticPopupDialogs["TSM_CRAFTING_CLEAR_QUEUE"] or {
|
||||
text = L["Are you sure you want to clear the entire queue?"],
|
||||
button1 = YES,
|
||||
button2 = CANCEL,
|
||||
timeout = 0,
|
||||
hideOnEscape = true,
|
||||
OnAccept = function()
|
||||
TSM.Queue:ClearQueue()
|
||||
GUI:UpdateQueue()
|
||||
if GUI.frame.gather:IsVisible() then
|
||||
GUI.frame.gather:Hide()
|
||||
end
|
||||
private.gather = {}
|
||||
GUI:UpdateGatherSelectionWindow()
|
||||
if GUI.gatheringFrame:IsShown() then
|
||||
GUI.gatheringFrame:Hide()
|
||||
TSM.db.realm.gathering.crafter = nil
|
||||
TSM.db.realm.gathering.neededMats = {}
|
||||
TSM.db.realm.gathering.gatheredMats = false
|
||||
TSM.db.realm.sourceStatus.collapsed = {}
|
||||
end
|
||||
end,
|
||||
preferredIndex = 3,
|
||||
}
|
||||
TSMAPI:ShowStaticPopupDialog("TSM_CRAFTING_CLEAR_QUEUE")
|
||||
end)
|
||||
frame.clearBtn = btn
|
||||
|
||||
|
|
@ -2041,7 +2065,12 @@ function GUI:CreateGatheringSelectionFrame(parent)
|
|||
dropdown:SetMultiselect(true)
|
||||
dropdown:SetCallback("OnValueChanged", function(_, _, profession, value)
|
||||
private.gather.professions[profession] = value or nil
|
||||
GUI:UpdateGatherSelectionWindow()
|
||||
-- Only update the button state, don't rebuild the dropdown list
|
||||
if next(private.gather.professions) then
|
||||
frame.gatherButton:Enable()
|
||||
else
|
||||
frame.gatherButton:Disable()
|
||||
end
|
||||
end)
|
||||
frame.professionDropdown = dropdown
|
||||
|
||||
|
|
@ -2622,8 +2651,19 @@ function GUI:GatheringEventHandler(event)
|
|||
if not GUI.gatheringFrame or not GUI.gatheringFrame:IsShown() then return end
|
||||
|
||||
if event == "GUILDBANKFRAME_OPENED" then
|
||||
private.currentSource = UnitName("player")
|
||||
private.currentTask = L["Visit Guild Bank"]
|
||||
-- Ascension WoW: Detect bank type based on first tab name
|
||||
local numTabs = GetNumGuildBankTabs()
|
||||
local firstTabName = numTabs > 0 and GetGuildBankTabInfo(1) or nil
|
||||
if firstTabName == "Personal Bank" then
|
||||
private.currentSource = UnitName("player")
|
||||
private.currentTask = L["Visit Personal Bank"]
|
||||
elseif firstTabName == "Realm Bank" then
|
||||
private.currentSource = L["Realm Bank"]
|
||||
private.currentTask = L["Visit Realm Bank"]
|
||||
else
|
||||
private.currentSource = UnitName("player")
|
||||
private.currentTask = L["Visit Guild Bank"]
|
||||
end
|
||||
elseif event == "GUILDBANKFRAME_CLOSED" then
|
||||
private.currentSource = nil
|
||||
private.currentTask = nil
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ function Gather:gatherItems(source, task)
|
|||
|
||||
if source == L["Vendor"] then
|
||||
Gather:BuyFromMerchant(items)
|
||||
elseif source == UnitName("player") and (task == L["Visit Bank"] or task == L["Visit Guild Bank"]) then
|
||||
elseif (source == UnitName("player") or source == L["Realm Bank"]) and (task == L["Visit Bank"] or task == L["Visit Guild Bank"] or task == L["Visit Personal Bank"] or task == L["Visit Realm Bank"]) then
|
||||
Gather:GatherBank(items)
|
||||
elseif source == UnitName("player") and task == L["Mail Items"] then
|
||||
Gather:MailItems(items)
|
||||
|
|
|
|||
|
|
@ -1,340 +1,416 @@
|
|||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster_Crafting --
|
||||
-- http://www.curse.com/addons/wow/tradeskillmaster_crafting --
|
||||
-- --
|
||||
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
|
||||
-- All Rights Reserved* - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
-- load the parent file (TSM) into a local variable and register this file as a module
|
||||
local TSM = select(2, ...)
|
||||
local Inventory = TSM:NewModule("Inventory", "AceEvent-3.0")
|
||||
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Crafting") -- loads the localization table
|
||||
|
||||
|
||||
-- gets the number of an item in the current player's bags
|
||||
function Inventory:GetPlayerBagNum(itemString)
|
||||
if not itemString then return end
|
||||
|
||||
if TSMAPI.SOULBOUND_MATS[itemString] then
|
||||
return GetItemCount(itemString)
|
||||
else
|
||||
local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", UnitName("player")) or {}
|
||||
return bags and bags[itemString] or 0
|
||||
end
|
||||
end
|
||||
|
||||
function Inventory:GetTotals()
|
||||
local bagTotal, auctionTotal, otherTotal, total = {}, {}, {}, {}
|
||||
|
||||
for _, player in pairs(TSMAPI:ModuleAPI("ItemTracker", "playerlist") or {}) do
|
||||
if player == UnitName("player") or not TSM.db.global.ignoreCharacters[player] then
|
||||
local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", player) or {}
|
||||
local bank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", player) or {}
|
||||
local mail = TSMAPI:ModuleAPI("ItemTracker", "playermail", player) or {}
|
||||
local auctions = TSMAPI:ModuleAPI("ItemTracker", "playerauctions", player) or {}
|
||||
for itemString, quantity in pairs(bags) do
|
||||
if player == UnitName("player") then
|
||||
bagTotal[itemString] = (bagTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
else
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
for itemString, quantity in pairs(bank) do
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
for itemString, quantity in pairs(mail) do
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
for itemString, quantity in pairs(auctions) do
|
||||
auctionTotal[itemString] = (auctionTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for itemString in pairs(TSMAPI.SOULBOUND_MATS) do
|
||||
local bagNum = GetItemCount(itemString)
|
||||
local bankNum = GetItemCount(itemString, true) - GetItemCount(itemString)
|
||||
bagTotal[itemString] = (bagTotal[itemString] or 0) + bagNum
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + bankNum
|
||||
total[itemString] = (total[itemString] or 0) + bagNum + bankNum
|
||||
end
|
||||
|
||||
-- add gbank counts of all non-ignored guilds
|
||||
for _, guild in pairs(TSMAPI:ModuleAPI("ItemTracker", "guildlist") or {}) do
|
||||
if not TSM.db.global.ignoreGuilds[guild] then
|
||||
local gbank = TSMAPI:ModuleAPI("ItemTracker", "guildbank", guild) or {}
|
||||
for itemString, quantity in pairs(gbank) do
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
return bagTotal, auctionTotal, otherTotal, total
|
||||
end
|
||||
|
||||
-- gets the total number of some item that they have
|
||||
function Inventory:GetTotalQuantity(itemString)
|
||||
if not itemString then return 0 end
|
||||
local count = 0
|
||||
|
||||
-- add bags/bank/mail/auction counts of all non-ignored characters (always including current character)
|
||||
for _, player in pairs(TSMAPI:ModuleAPI("ItemTracker", "playerlist") or {}) do
|
||||
if player == UnitName("player") or not TSM.db.global.ignoreCharacters[player] then
|
||||
local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", player) or {}
|
||||
local bank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", player) or {}
|
||||
local mail = TSMAPI:ModuleAPI("ItemTracker", "playermail", player) or {}
|
||||
local auctions = TSMAPI:ModuleAPI("ItemTracker", "playerauctions", player) or {}
|
||||
count = count + (bags[itemString] or 0)
|
||||
count = count + (bank[itemString] or 0)
|
||||
count = count + (mail[itemString] or 0)
|
||||
count = count + (auctions[itemString] or 0)
|
||||
end
|
||||
end
|
||||
-- add gbank counts of all non-ignored guilds
|
||||
for _, guild in pairs(TSMAPI:ModuleAPI("ItemTracker", "guildlist") or {}) do
|
||||
if not TSM.db.global.ignoreGuilds[guild] then
|
||||
local bank = TSMAPI:ModuleAPI("ItemTracker", "guildbank", guild) or {}
|
||||
count = count + (bank[itemString] or 0)
|
||||
end
|
||||
end
|
||||
|
||||
if TSMAPI.SOULBOUND_MATS[itemString] then
|
||||
count = count + GetItemCount(itemString, true)
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
function Inventory:GetItemSources(crafter, neededMats)
|
||||
if not neededMats then return end
|
||||
local sources = {}
|
||||
local gbank = {}
|
||||
local next = next
|
||||
local crafterBags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", crafter) or {}
|
||||
local crafterMail = TSMAPI:ModuleAPI("ItemTracker", "playermail", crafter) or {}
|
||||
local crafterBank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", crafter) or {}
|
||||
|
||||
-- add vendor items
|
||||
local task = {}
|
||||
local items = {}
|
||||
for itemString, quantity in pairs(neededMats) do
|
||||
if TSMAPI:GetVendorCost(itemString) then
|
||||
local vendorNeed = quantity - ((crafterBags[itemString] or 0) + (crafterMail[itemString] or 0) + (crafterBank[itemString] or 0))
|
||||
if vendorNeed > 0 then
|
||||
items[itemString] = vendorNeed
|
||||
end
|
||||
elseif TSMAPI.Conversions[itemString] and TSMAPI.InkConversions[itemString] then
|
||||
local tradeItem, data = next(TSMAPI.Conversions[itemString])
|
||||
if data.source == "vendortrade" then
|
||||
local num = floor(Inventory:GetTotalQuantity(tradeItem) * data.rate)
|
||||
if quantity > Inventory:GetTotalQuantity(itemString) and num >= (quantity - Inventory:GetTotalQuantity(itemString)) then
|
||||
items[itemString] = quantity - Inventory:GetTotalQuantity(itemString)
|
||||
neededMats[tradeItem] = (neededMats[tradeItem] or 0) + quantity / data.rate -- add the qty of IOD to needed mats
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(items) then
|
||||
tinsert(task, { taskType = L["Visit Vendor"], items = items })
|
||||
tinsert(sources, { sourceName = L["Vendor"], isCrafter = false, isVendor = true, isAH = false, tasks = task })
|
||||
end
|
||||
|
||||
-- double check if crafter already has all the items needed
|
||||
local shortItems = {}
|
||||
for itemString, quantity in pairs(neededMats) do
|
||||
local soulboundBagCount
|
||||
if TSMAPI.SOULBOUND_MATS[itemString] then
|
||||
soulboundBagCount = GetItemCount(itemString)
|
||||
end
|
||||
local need = max(quantity - (crafterBags[itemString] or soulboundBagCount or 0), 0)
|
||||
if need > 0 then
|
||||
shortItems[itemString] = need
|
||||
end
|
||||
end
|
||||
if not next(shortItems) then return end
|
||||
|
||||
-- add bags/bank/mail "tasks" for needed items of all non-ignored characters (always include crafter)
|
||||
for _, player in pairs(TSMAPI:ModuleAPI("ItemTracker", "playerlist") or {}) do
|
||||
if player == crafter or not TSM.db.global.ignoreCharacters[player] then
|
||||
local task = {}
|
||||
local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", player) or {}
|
||||
local bank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", player) or {}
|
||||
local guild = TSMAPI:ModuleAPI("ItemTracker", "playerguild", player) or {}
|
||||
local gbank = {}
|
||||
if guild and not TSM.db.global.ignoreGuilds[guild] then
|
||||
gbank = TSMAPI:ModuleAPI("ItemTracker", "guildbank", guild) or {}
|
||||
end
|
||||
local mail = TSMAPI:ModuleAPI("ItemTracker", "playermail", player) or {}
|
||||
local bankItems = {}
|
||||
local gbankItems = {}
|
||||
local mailItems = {}
|
||||
local bagItems = {}
|
||||
|
||||
for itemString in pairs(neededMats) do
|
||||
local soulboundBagCount, soulboundBankCount
|
||||
if TSMAPI.SOULBOUND_MATS[itemString] then
|
||||
soulboundBagCount = GetItemCount(itemString)
|
||||
soulboundBankCount = GetItemCount(itemString, true) - soulboundBagCount
|
||||
end
|
||||
if (bank[itemString] or (soulboundBankCount and soulboundBankCount > 0)) and shortItems[itemString] then
|
||||
if shortItems[itemString] - (crafterMail[itemString] or 0) - (player ~= crafter and bags[itemString] or 0) > 0 then
|
||||
bankItems[itemString] = bank[itemString] or soulboundBankCount
|
||||
end
|
||||
end
|
||||
if gbank[itemString] and shortItems[itemString] then
|
||||
if shortItems[itemString] - (crafterMail[itemString] or 0) - (player ~= crafter and bags[itemString] or 0) > 0 then
|
||||
gbankItems[itemString] = gbank[itemString]
|
||||
end
|
||||
end
|
||||
if mail[itemString] and shortItems[itemString] then
|
||||
mailItems[itemString] = mail[itemString]
|
||||
end
|
||||
if bags[itemString] and shortItems[itemString] then
|
||||
if player ~= crafter then
|
||||
if shortItems[itemString] - (crafterMail[itemString] or 0) > 0 then
|
||||
bagItems[itemString] = bags[itemString]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- add mail tasks for destroyable items bought through shopping search (exclude items already added to mail tasks)
|
||||
for itemString, quantity in pairs(TSM.db.realm.gathering.destroyingMats) do
|
||||
if mail[itemString] and not shortItems[itemString] then
|
||||
mailItems[itemString] = quantity
|
||||
end
|
||||
end
|
||||
|
||||
if next(bankItems) then
|
||||
tinsert(task, { taskType = L["Visit Bank"], items = bankItems })
|
||||
end
|
||||
if next(gbankItems) then
|
||||
tinsert(task, { taskType = L["Visit Guild Bank"], items = gbankItems })
|
||||
end
|
||||
if next(mailItems) then
|
||||
tinsert(task, { taskType = L["Collect Mail"], items = mailItems })
|
||||
end
|
||||
if next(bagItems) then
|
||||
tinsert(task, { taskType = L["Mail Items"], items = bagItems })
|
||||
end
|
||||
if next(task) then
|
||||
tinsert(sources, { sourceName = player, isCrafter = player == crafter, isVendor = false, isAH = false, tasks = task, isCurrent = (player == UnitName("player")) })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- add auction house tasks
|
||||
local auctionTask = {}
|
||||
local auctionItems = {}
|
||||
for itemString, quantity in pairs(neededMats) do
|
||||
if not TSMAPI.SOULBOUND_MATS[itemString] and not TSMAPI:GetVendorCost(itemString) then
|
||||
local need
|
||||
if TSM.Inventory.gatherItem == itemString and TSM.Inventory.gatherQuantity then
|
||||
need = TSM.Inventory.gatherQuantity
|
||||
else
|
||||
need = max(quantity - (TSM.Inventory:GetTotalQuantity(itemString) or 0), 0)
|
||||
end
|
||||
if need > 0 then
|
||||
auctionItems[itemString] = need
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(auctionItems) then
|
||||
tinsert(auctionTask, { taskType = L["Search for Mats"], items = auctionItems })
|
||||
tinsert(sources, { sourceName = L["Auction House"], isCrafter = false, isVendor = false, isAH = true, tasks = auctionTask })
|
||||
end
|
||||
|
||||
-- add destroying tasks
|
||||
local destroyingTask, millItems, prospectItems, transformItems, deItems = {}, {}, {}, {}, {}
|
||||
|
||||
for itemString, quantity in pairs(neededMats) do
|
||||
local need = max(quantity - (TSM.Inventory:GetTotalQuantity(itemString) or 0), 0)
|
||||
-- conversion items
|
||||
for destroyItem, data in pairs(TSMAPI.Conversions[itemString] or {}) do
|
||||
if TSM.db.realm.gathering.destroyingMats[destroyItem] then
|
||||
if need > 0 then
|
||||
local destroyNeed
|
||||
if data.source == "mill" then
|
||||
destroyNeed = floor(TSM.db.realm.gathering.destroyingMats[destroyItem] / 5)
|
||||
if destroyNeed > 0 then
|
||||
millItems[destroyItem] = (millItems[destroyItem] or 0) + destroyNeed
|
||||
end
|
||||
elseif data.source == "prospect" then
|
||||
destroyNeed = floor(TSM.db.realm.gathering.destroyingMats[destroyItem] / 5)
|
||||
if destroyNeed > 0 then
|
||||
prospectItems[destroyItem] = (prospectItems[destroyItem] or 0) + destroyNeed
|
||||
end
|
||||
elseif data.source == "transform" then
|
||||
if data.rate == 1 / 3 then
|
||||
destroyNeed = floor(TSM.db.realm.gathering.destroyingMats[destroyItem] / 3)
|
||||
elseif data.rate == 1 / 10 then
|
||||
destroyNeed = floor(TSM.db.realm.gathering.destroyingMats[destroyItem] / 10)
|
||||
else
|
||||
destroyNeed = TSM.db.realm.gathering.destroyingMats[destroyItem]
|
||||
end
|
||||
if destroyNeed > 0 then
|
||||
transformItems[destroyItem] = (transformItems[destroyItem] or 0) + destroyNeed
|
||||
end
|
||||
end
|
||||
else
|
||||
TSM.db.realm.gathering.destroyingMats[destroyItem] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
-- disenchantable items
|
||||
if next(TSM.db.realm.gathering.destroyingMats) then
|
||||
for deItemString, quantity in pairs(TSM.db.realm.gathering.destroyingMats) do
|
||||
if Inventory:IsDisenchantable(deItemString) then
|
||||
if need > 0 then
|
||||
deItems[deItemString] = quantity
|
||||
else
|
||||
TSM.db.realm.gathering.destroyingMats[deItemString] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if next(millItems) then
|
||||
tinsert(destroyingTask, { taskType = L["Milling"], items = millItems })
|
||||
end
|
||||
if next(prospectItems) then
|
||||
tinsert(destroyingTask, { taskType = L["Prospect"], items = prospectItems })
|
||||
end
|
||||
if next(transformItems) then
|
||||
tinsert(destroyingTask, { taskType = L["Transform"], items = transformItems })
|
||||
end
|
||||
if next(deItems) then
|
||||
tinsert(destroyingTask, { taskType = L["Disenchant"], items = deItems })
|
||||
end
|
||||
if next(destroyingTask) then
|
||||
tinsert(sources, { sourceName = L["Destroying"], isCrafter = false, isVendor = false, isAH = true, tasks = destroyingTask })
|
||||
end
|
||||
|
||||
|
||||
sort(sources, function(a, b)
|
||||
if a.isCurrent then return true end
|
||||
if b.isCurrent then return false end
|
||||
if a.isAH then return false end
|
||||
if b.isAH then return true end
|
||||
if a.isVendor then return false end
|
||||
if b.isVendor then return true end
|
||||
if a.isCrafter then return false end
|
||||
if b.isCrafter then return true end
|
||||
return a.sourceName < b.sourceName
|
||||
end)
|
||||
return sources
|
||||
end
|
||||
|
||||
function Inventory:IsDisenchantable(itemString)
|
||||
local _, link, quality, _, _, iType = TSMAPI:GetSafeItemInfo(itemString)
|
||||
local WEAPON, ARMOR = GetAuctionItemClasses()
|
||||
if itemString and not TSMAPI.DisenchantingData.notDisenchantable[itemString] and (iType == ARMOR or iType == WEAPON) then
|
||||
return true
|
||||
end
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster_Crafting --
|
||||
-- http://www.curse.com/addons/wow/tradeskillmaster_crafting --
|
||||
-- --
|
||||
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
|
||||
-- All Rights Reserved* - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
-- load the parent file (TSM) into a local variable and register this file as a module
|
||||
local TSM = select(2, ...)
|
||||
local Inventory = TSM:NewModule("Inventory", "AceEvent-3.0")
|
||||
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Crafting") -- loads the localization table
|
||||
|
||||
|
||||
-- gets the number of an item in the current player's bags
|
||||
function Inventory:GetPlayerBagNum(itemString)
|
||||
if not itemString then return end
|
||||
|
||||
if TSMAPI.SOULBOUND_MATS[itemString] then
|
||||
return GetItemCount(itemString)
|
||||
else
|
||||
local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", UnitName("player")) or {}
|
||||
return bags and bags[itemString] or 0
|
||||
end
|
||||
end
|
||||
|
||||
function Inventory:GetTotals()
|
||||
local bagTotal, auctionTotal, otherTotal, total = {}, {}, {}, {}
|
||||
|
||||
for _, player in pairs(TSMAPI:ModuleAPI("ItemTracker", "playerlist") or {}) do
|
||||
if player == UnitName("player") or not TSM.db.global.ignoreCharacters[player] then
|
||||
local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", player) or {}
|
||||
local bank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", player) or {}
|
||||
local mail = TSMAPI:ModuleAPI("ItemTracker", "playermail", player) or {}
|
||||
local auctions = TSMAPI:ModuleAPI("ItemTracker", "playerauctions", player) or {}
|
||||
for itemString, quantity in pairs(bags) do
|
||||
if player == UnitName("player") then
|
||||
bagTotal[itemString] = (bagTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
else
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
for itemString, quantity in pairs(bank) do
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
for itemString, quantity in pairs(mail) do
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
for itemString, quantity in pairs(auctions) do
|
||||
auctionTotal[itemString] = (auctionTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for itemString in pairs(TSMAPI.SOULBOUND_MATS) do
|
||||
local bagNum = GetItemCount(itemString)
|
||||
local bankNum = GetItemCount(itemString, true) - GetItemCount(itemString)
|
||||
bagTotal[itemString] = (bagTotal[itemString] or 0) + bagNum
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + bankNum
|
||||
total[itemString] = (total[itemString] or 0) + bagNum + bankNum
|
||||
end
|
||||
|
||||
-- add gbank counts of all non-ignored guilds
|
||||
for _, guild in pairs(TSMAPI:ModuleAPI("ItemTracker", "guildlist") or {}) do
|
||||
if not TSM.db.global.ignoreGuilds[guild] then
|
||||
local gbank = TSMAPI:ModuleAPI("ItemTracker", "guildbank", guild) or {}
|
||||
for itemString, quantity in pairs(gbank) do
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Ascension WoW: add personal bank counts for all non-ignored characters
|
||||
for _, player in pairs(TSMAPI:ModuleAPI("ItemTracker", "playerlist") or {}) do
|
||||
if player == UnitName("player") or not TSM.db.global.ignoreCharacters[player] then
|
||||
local personalBank = TSMAPI:ModuleAPI("ItemTracker", "personalbank", player) or {}
|
||||
for itemString, quantity in pairs(personalBank) do
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Ascension WoW: add realm bank counts
|
||||
local realmBank = TSMAPI:ModuleAPI("ItemTracker", "realmbank") or {}
|
||||
for itemString, quantity in pairs(realmBank) do
|
||||
otherTotal[itemString] = (otherTotal[itemString] or 0) + quantity
|
||||
total[itemString] = (total[itemString] or 0) + quantity
|
||||
end
|
||||
|
||||
return bagTotal, auctionTotal, otherTotal, total
|
||||
end
|
||||
|
||||
-- gets the total number of some item that they have
|
||||
function Inventory:GetTotalQuantity(itemString)
|
||||
if not itemString then return 0 end
|
||||
local count = 0
|
||||
|
||||
-- add bags/bank/mail/auction counts of all non-ignored characters (always including current character)
|
||||
for _, player in pairs(TSMAPI:ModuleAPI("ItemTracker", "playerlist") or {}) do
|
||||
if player == UnitName("player") or not TSM.db.global.ignoreCharacters[player] then
|
||||
local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", player) or {}
|
||||
local bank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", player) or {}
|
||||
local mail = TSMAPI:ModuleAPI("ItemTracker", "playermail", player) or {}
|
||||
local auctions = TSMAPI:ModuleAPI("ItemTracker", "playerauctions", player) or {}
|
||||
count = count + (bags[itemString] or 0)
|
||||
count = count + (bank[itemString] or 0)
|
||||
count = count + (mail[itemString] or 0)
|
||||
count = count + (auctions[itemString] or 0)
|
||||
end
|
||||
end
|
||||
-- add gbank counts of all non-ignored guilds
|
||||
for _, guild in pairs(TSMAPI:ModuleAPI("ItemTracker", "guildlist") or {}) do
|
||||
if not TSM.db.global.ignoreGuilds[guild] then
|
||||
local bank = TSMAPI:ModuleAPI("ItemTracker", "guildbank", guild) or {}
|
||||
count = count + (bank[itemString] or 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Ascension WoW: add personal bank counts for all non-ignored characters
|
||||
for _, player in pairs(TSMAPI:ModuleAPI("ItemTracker", "playerlist") or {}) do
|
||||
if player == UnitName("player") or not TSM.db.global.ignoreCharacters[player] then
|
||||
local personalBank = TSMAPI:ModuleAPI("ItemTracker", "personalbank", player) or {}
|
||||
count = count + (personalBank[itemString] or 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Ascension WoW: add realm bank count
|
||||
local realmBank = TSMAPI:ModuleAPI("ItemTracker", "realmbank") or {}
|
||||
count = count + (realmBank[itemString] or 0)
|
||||
|
||||
if TSMAPI.SOULBOUND_MATS[itemString] then
|
||||
count = count + GetItemCount(itemString, true)
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
function Inventory:GetItemSources(crafter, neededMats)
|
||||
if not neededMats then return end
|
||||
local sources = {}
|
||||
local gbank = {}
|
||||
local next = next
|
||||
local crafterBags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", crafter) or {}
|
||||
local crafterMail = TSMAPI:ModuleAPI("ItemTracker", "playermail", crafter) or {}
|
||||
local crafterBank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", crafter) or {}
|
||||
-- Ascension WoW: crafter's personal bank
|
||||
local crafterPersonalBank = TSMAPI:ModuleAPI("ItemTracker", "personalbank", crafter) or {}
|
||||
|
||||
-- add vendor items
|
||||
local task = {}
|
||||
local items = {}
|
||||
for itemString, quantity in pairs(neededMats) do
|
||||
if TSMAPI:GetVendorCost(itemString) then
|
||||
local vendorNeed = quantity - ((crafterBags[itemString] or 0) + (crafterMail[itemString] or 0) + (crafterBank[itemString] or 0) + (crafterPersonalBank[itemString] or 0))
|
||||
if vendorNeed > 0 then
|
||||
items[itemString] = vendorNeed
|
||||
end
|
||||
elseif TSMAPI.Conversions[itemString] and TSMAPI.InkConversions[itemString] then
|
||||
local tradeItem, data = next(TSMAPI.Conversions[itemString])
|
||||
if data.source == "vendortrade" then
|
||||
local num = floor(Inventory:GetTotalQuantity(tradeItem) * data.rate)
|
||||
if quantity > Inventory:GetTotalQuantity(itemString) and num >= (quantity - Inventory:GetTotalQuantity(itemString)) then
|
||||
items[itemString] = quantity - Inventory:GetTotalQuantity(itemString)
|
||||
neededMats[tradeItem] = (neededMats[tradeItem] or 0) + quantity / data.rate -- add the qty of IOD to needed mats
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(items) then
|
||||
tinsert(task, { taskType = L["Visit Vendor"], items = items })
|
||||
tinsert(sources, { sourceName = L["Vendor"], isCrafter = false, isVendor = true, isAH = false, tasks = task })
|
||||
end
|
||||
|
||||
-- double check if crafter already has all the items needed
|
||||
local shortItems = {}
|
||||
for itemString, quantity in pairs(neededMats) do
|
||||
local soulboundBagCount
|
||||
if TSMAPI.SOULBOUND_MATS[itemString] then
|
||||
soulboundBagCount = GetItemCount(itemString)
|
||||
end
|
||||
local inBags = crafterBags[itemString] or soulboundBagCount or 0
|
||||
local need = max(quantity - inBags, 0)
|
||||
if need > 0 then
|
||||
shortItems[itemString] = need
|
||||
end
|
||||
end
|
||||
if not next(shortItems) then
|
||||
return sources -- Return sources instead of nil so vendor items are not lost
|
||||
end
|
||||
|
||||
-- add bags/bank/mail "tasks" for needed items of all non-ignored characters (always include crafter)
|
||||
local playerList = TSMAPI:ModuleAPI("ItemTracker", "playerlist") or {}
|
||||
|
||||
for _, player in pairs(playerList) do
|
||||
if player == crafter or not TSM.db.global.ignoreCharacters[player] then
|
||||
local task = {}
|
||||
local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", player) or {}
|
||||
local bank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", player) or {}
|
||||
local guild = TSMAPI:ModuleAPI("ItemTracker", "playerguild", player) or {}
|
||||
local gbank = {}
|
||||
if guild and not TSM.db.global.ignoreGuilds[guild] then
|
||||
gbank = TSMAPI:ModuleAPI("ItemTracker", "guildbank", guild) or {}
|
||||
end
|
||||
local mail = TSMAPI:ModuleAPI("ItemTracker", "playermail", player) or {}
|
||||
-- Ascension WoW: personal bank for this player
|
||||
local personalBank = TSMAPI:ModuleAPI("ItemTracker", "personalbank", player) or {}
|
||||
local bankItems = {}
|
||||
local gbankItems = {}
|
||||
local mailItems = {}
|
||||
local bagItems = {}
|
||||
local personalBankItems = {}
|
||||
|
||||
for itemString in pairs(neededMats) do
|
||||
local soulboundBagCount, soulboundBankCount
|
||||
if TSMAPI.SOULBOUND_MATS[itemString] then
|
||||
soulboundBagCount = GetItemCount(itemString)
|
||||
soulboundBankCount = GetItemCount(itemString, true) - soulboundBagCount
|
||||
end
|
||||
if (bank[itemString] or (soulboundBankCount and soulboundBankCount > 0)) and shortItems[itemString] then
|
||||
if shortItems[itemString] - (crafterMail[itemString] or 0) - (player ~= crafter and bags[itemString] or 0) > 0 then
|
||||
bankItems[itemString] = bank[itemString] or soulboundBankCount
|
||||
end
|
||||
end
|
||||
if gbank[itemString] and shortItems[itemString] then
|
||||
if shortItems[itemString] - (crafterMail[itemString] or 0) - (player ~= crafter and bags[itemString] or 0) > 0 then
|
||||
gbankItems[itemString] = gbank[itemString]
|
||||
end
|
||||
end
|
||||
-- Ascension WoW: check personal bank
|
||||
if personalBank[itemString] and shortItems[itemString] then
|
||||
if shortItems[itemString] - (crafterMail[itemString] or 0) - (player ~= crafter and bags[itemString] or 0) > 0 then
|
||||
personalBankItems[itemString] = personalBank[itemString]
|
||||
end
|
||||
end
|
||||
if mail[itemString] and shortItems[itemString] then
|
||||
mailItems[itemString] = mail[itemString]
|
||||
end
|
||||
if bags[itemString] and shortItems[itemString] then
|
||||
if player ~= crafter then
|
||||
if shortItems[itemString] - (crafterMail[itemString] or 0) > 0 then
|
||||
bagItems[itemString] = bags[itemString]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- add mail tasks for destroyable items bought through shopping search (exclude items already added to mail tasks)
|
||||
for itemString, quantity in pairs(TSM.db.realm.gathering.destroyingMats) do
|
||||
if mail[itemString] and not shortItems[itemString] then
|
||||
mailItems[itemString] = quantity
|
||||
end
|
||||
end
|
||||
|
||||
if next(bankItems) then
|
||||
tinsert(task, { taskType = L["Visit Bank"], items = bankItems })
|
||||
end
|
||||
if next(gbankItems) then
|
||||
tinsert(task, { taskType = L["Visit Guild Bank"], items = gbankItems })
|
||||
end
|
||||
-- Ascension WoW: personal bank task
|
||||
if next(personalBankItems) then
|
||||
tinsert(task, { taskType = L["Visit Personal Bank"], items = personalBankItems })
|
||||
end
|
||||
if next(mailItems) then
|
||||
tinsert(task, { taskType = L["Collect Mail"], items = mailItems })
|
||||
end
|
||||
if next(bagItems) then
|
||||
tinsert(task, { taskType = L["Mail Items"], items = bagItems })
|
||||
end
|
||||
if next(task) then
|
||||
tinsert(sources, { sourceName = player, isCrafter = player == crafter, isVendor = false, isAH = false, tasks = task, isCurrent = (player == UnitName("player")) })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Ascension WoW: add realm bank as a separate source
|
||||
local realmBank = TSMAPI:ModuleAPI("ItemTracker", "realmbank") or {}
|
||||
local realmBankTask = {}
|
||||
local realmBankItems = {}
|
||||
for itemString in pairs(neededMats) do
|
||||
if realmBank[itemString] and shortItems[itemString] then
|
||||
if shortItems[itemString] - (crafterMail[itemString] or 0) > 0 then
|
||||
realmBankItems[itemString] = realmBank[itemString]
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(realmBankItems) then
|
||||
tinsert(realmBankTask, { taskType = L["Visit Realm Bank"], items = realmBankItems })
|
||||
tinsert(sources, { sourceName = L["Realm Bank"], isCrafter = false, isVendor = false, isAH = false, tasks = realmBankTask, isCurrent = true })
|
||||
end
|
||||
|
||||
-- add auction house tasks
|
||||
local auctionTask = {}
|
||||
local auctionItems = {}
|
||||
for itemString, quantity in pairs(neededMats) do
|
||||
if not TSMAPI.SOULBOUND_MATS[itemString] and not TSMAPI:GetVendorCost(itemString) then
|
||||
local need
|
||||
if TSM.Inventory.gatherItem == itemString and TSM.Inventory.gatherQuantity then
|
||||
need = TSM.Inventory.gatherQuantity
|
||||
else
|
||||
need = max(quantity - (TSM.Inventory:GetTotalQuantity(itemString) or 0), 0)
|
||||
end
|
||||
if need > 0 then
|
||||
auctionItems[itemString] = need
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(auctionItems) then
|
||||
tinsert(auctionTask, { taskType = L["Search for Mats"], items = auctionItems })
|
||||
tinsert(sources, { sourceName = L["Auction House"], isCrafter = false, isVendor = false, isAH = true, tasks = auctionTask })
|
||||
end
|
||||
|
||||
-- add destroying tasks
|
||||
local destroyingTask, millItems, prospectItems, transformItems, deItems = {}, {}, {}, {}, {}
|
||||
|
||||
for itemString, quantity in pairs(neededMats) do
|
||||
local need = max(quantity - (TSM.Inventory:GetTotalQuantity(itemString) or 0), 0)
|
||||
-- conversion items
|
||||
for destroyItem, data in pairs(TSMAPI.Conversions[itemString] or {}) do
|
||||
if TSM.db.realm.gathering.destroyingMats[destroyItem] then
|
||||
if need > 0 then
|
||||
local destroyNeed
|
||||
if data.source == "mill" then
|
||||
destroyNeed = floor(TSM.db.realm.gathering.destroyingMats[destroyItem] / 5)
|
||||
if destroyNeed > 0 then
|
||||
millItems[destroyItem] = (millItems[destroyItem] or 0) + destroyNeed
|
||||
end
|
||||
elseif data.source == "prospect" then
|
||||
destroyNeed = floor(TSM.db.realm.gathering.destroyingMats[destroyItem] / 5)
|
||||
if destroyNeed > 0 then
|
||||
prospectItems[destroyItem] = (prospectItems[destroyItem] or 0) + destroyNeed
|
||||
end
|
||||
elseif data.source == "transform" then
|
||||
if data.rate == 1 / 3 then
|
||||
destroyNeed = floor(TSM.db.realm.gathering.destroyingMats[destroyItem] / 3)
|
||||
elseif data.rate == 1 / 10 then
|
||||
destroyNeed = floor(TSM.db.realm.gathering.destroyingMats[destroyItem] / 10)
|
||||
else
|
||||
destroyNeed = TSM.db.realm.gathering.destroyingMats[destroyItem]
|
||||
end
|
||||
if destroyNeed > 0 then
|
||||
transformItems[destroyItem] = (transformItems[destroyItem] or 0) + destroyNeed
|
||||
end
|
||||
end
|
||||
else
|
||||
TSM.db.realm.gathering.destroyingMats[destroyItem] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
-- disenchantable items
|
||||
if next(TSM.db.realm.gathering.destroyingMats) then
|
||||
for deItemString, quantity in pairs(TSM.db.realm.gathering.destroyingMats) do
|
||||
if Inventory:IsDisenchantable(deItemString) then
|
||||
if need > 0 then
|
||||
deItems[deItemString] = quantity
|
||||
else
|
||||
TSM.db.realm.gathering.destroyingMats[deItemString] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if next(millItems) then
|
||||
tinsert(destroyingTask, { taskType = L["Milling"], items = millItems })
|
||||
end
|
||||
if next(prospectItems) then
|
||||
tinsert(destroyingTask, { taskType = L["Prospect"], items = prospectItems })
|
||||
end
|
||||
if next(transformItems) then
|
||||
tinsert(destroyingTask, { taskType = L["Transform"], items = transformItems })
|
||||
end
|
||||
if next(deItems) then
|
||||
tinsert(destroyingTask, { taskType = L["Disenchant"], items = deItems })
|
||||
end
|
||||
if next(destroyingTask) then
|
||||
tinsert(sources, { sourceName = L["Destroying"], isCrafter = false, isVendor = false, isAH = true, tasks = destroyingTask })
|
||||
end
|
||||
|
||||
|
||||
sort(sources, function(a, b)
|
||||
-- isCurrent sources come first
|
||||
if a.isCurrent ~= b.isCurrent then
|
||||
return a.isCurrent
|
||||
end
|
||||
-- AH sources come last
|
||||
if a.isAH ~= b.isAH then
|
||||
return b.isAH
|
||||
end
|
||||
-- Vendor sources come near last (before AH)
|
||||
if a.isVendor ~= b.isVendor then
|
||||
return b.isVendor
|
||||
end
|
||||
-- Crafter sources come after other players
|
||||
if a.isCrafter ~= b.isCrafter then
|
||||
return b.isCrafter
|
||||
end
|
||||
-- Alphabetical by name
|
||||
return a.sourceName < b.sourceName
|
||||
end)
|
||||
|
||||
return sources
|
||||
end
|
||||
|
||||
function Inventory:IsDisenchantable(itemString)
|
||||
local _, link, quality, _, _, iType = TSMAPI:GetSafeItemInfo(itemString)
|
||||
local WEAPON, ARMOR = GetAuctionItemClasses()
|
||||
if itemString and not TSMAPI.DisenchantingData.notDisenchantable[itemString] and (iType == ARMOR or iType == WEAPON) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
|
@ -29,5 +29,4 @@ Modules\Options.lua
|
|||
Modules\EnchantingInfo.lua
|
||||
Modules\Gather.lua
|
||||
Modules\Sync.lua
|
||||
Modules\SpellNames2IDs.lua
|
||||
Modules\VellumInfo.lua
|
||||
|
|
@ -14,9 +14,13 @@ local L = LibStub("AceLocale-3.0"):NewLocale("TradeSkillMaster_ItemTracker", "en
|
|||
if not L then return end
|
||||
|
||||
L["%s (%s bags, %s bank, %s AH, %s mail)"] = true
|
||||
L["%s (%s bags, %s bank, %s AH, %s mail, %s personal)"] = true
|
||||
L["%s in guild bank"] = true
|
||||
L["%s in realm bank"] = true
|
||||
L["%s item(s) total"] = true
|
||||
L["(%s player, %s alts, %s guild banks, %s AH)"] = true
|
||||
L["(%s player, %s alts, %s guild, %s AH, %s personal, %s realm)"] = true
|
||||
L["Realm Bank"] = true
|
||||
L["AH"] = true
|
||||
L["Bags"] = true
|
||||
L["Bank"] = true
|
||||
|
|
|
|||
|
|
@ -78,12 +78,32 @@ function Data:ThrottleEvent(event)
|
|||
throttleFrames[event]:Show()
|
||||
end
|
||||
|
||||
local BANK_TYPE_PERSONAL = "personal"
|
||||
local BANK_TYPE_REALM = "realm"
|
||||
local BANK_TYPE_GUILD = "guild"
|
||||
|
||||
local function GetCurrentBankType()
|
||||
if GuildBankFrame and GuildBankFrame.IsPersonalBank then
|
||||
return BANK_TYPE_PERSONAL
|
||||
elseif GuildBankFrame and GuildBankFrame.IsRealmBank then
|
||||
return BANK_TYPE_REALM
|
||||
else
|
||||
return BANK_TYPE_GUILD
|
||||
end
|
||||
end
|
||||
|
||||
-- Store the current bank type when opened (persists until next open)
|
||||
local currentOpenBankType = nil
|
||||
|
||||
function Data:EventHandler(event, fire)
|
||||
if isScanning then return end
|
||||
if fire ~= "FIRE" then
|
||||
Data:ThrottleEvent(event)
|
||||
else
|
||||
if event == "GUILDBANKFRAME_OPENED" then
|
||||
-- Detect and store the bank type
|
||||
currentOpenBankType = GetCurrentBankType()
|
||||
|
||||
-- Query all tabs of the gbank to ensure all tabs will be scanned.
|
||||
local initialTab = GetCurrentGuildBankTab()
|
||||
for tab = 1, GetNumGuildBankTabs() do
|
||||
|
|
@ -93,7 +113,14 @@ function Data:EventHandler(event, fire)
|
|||
end
|
||||
QueryGuildBankTab(initialTab)
|
||||
elseif event == "GUILDBANKBAGSLOTS_CHANGED" then
|
||||
Data:GetGuildBankData()
|
||||
-- Route to the appropriate handler based on bank type
|
||||
if currentOpenBankType == BANK_TYPE_PERSONAL then
|
||||
Data:GetPersonalBankData()
|
||||
elseif currentOpenBankType == BANK_TYPE_REALM then
|
||||
Data:GetRealmBankData()
|
||||
else
|
||||
Data:GetGuildBankData()
|
||||
end
|
||||
elseif event == "AUCTION_OWNED_LIST_UPDATE" then
|
||||
Data:ScanPlayerAuctions()
|
||||
end
|
||||
|
|
@ -128,7 +155,32 @@ function Data:GetBankData(state)
|
|||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
-- scan the guild bank
|
||||
-- Helper function to scan all guild bank slots and return items table
|
||||
local function ScanGuildBankSlots()
|
||||
local items = {}
|
||||
local numTabs = GetNumGuildBankTabs()
|
||||
for tab = 1, numTabs do
|
||||
local name, icon, isViewable, canDeposit, numWithdrawals = GetGuildBankTabInfo(tab)
|
||||
-- Ascension WoW: For Personal/Realm banks, always scan (numWithdrawals check may not apply)
|
||||
local canAccess = (numWithdrawals and numWithdrawals > 0) or IsGuildLeader(UnitName("player")) or (name == "Personal Bank") or (name == "Realm Bank")
|
||||
if canAccess then
|
||||
for slot = 1, MAX_GUILDBANK_SLOTS_PER_TAB or 98 do
|
||||
local itemString = TSMAPI:GetItemString(GetGuildBankItemLink(tab, slot))
|
||||
local baseItemString = TSMAPI:GetBaseItemString(GetGuildBankItemLink(tab, slot))
|
||||
if itemString then
|
||||
local quantity = select(2, GetGuildBankItemInfo(tab, slot))
|
||||
items[itemString] = (items[itemString] or 0) + quantity
|
||||
if itemString ~= baseItemString then
|
||||
items[baseItemString] = (items[baseItemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
-- scan the guild bank (real guild bank only)
|
||||
function Data:GetGuildBankData()
|
||||
if not TSM.CURRENT_GUILD then
|
||||
Data:StoreCurrentGuildInfo(true)
|
||||
|
|
@ -136,27 +188,53 @@ function Data:GetGuildBankData()
|
|||
end
|
||||
wipe(TSM.guilds[TSM.CURRENT_GUILD].items)
|
||||
|
||||
for tab = 1, GetNumGuildBankTabs() do
|
||||
if select(5, GetGuildBankTabInfo(tab)) > 0 or IsGuildLeader(UnitName("player")) then
|
||||
for slot = 1, MAX_GUILDBANK_SLOTS_PER_TAB or 98 do
|
||||
local itemString = TSMAPI:GetItemString(GetGuildBankItemLink(tab, slot))
|
||||
local baseItemString = TSMAPI:GetBaseItemString(GetGuildBankItemLink(tab, slot))
|
||||
if itemString then
|
||||
local quantity = select(2, GetGuildBankItemInfo(tab, slot))
|
||||
TSM.guilds[TSM.CURRENT_GUILD].items[itemString] = (TSM.guilds[TSM.CURRENT_GUILD].items[itemString] or 0) + quantity
|
||||
if itemString ~= baseItemString then
|
||||
TSM.guilds[TSM.CURRENT_GUILD].items[baseItemString] = (TSM.guilds[TSM.CURRENT_GUILD].items[baseItemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local items = ScanGuildBankSlots()
|
||||
for itemString, quantity in pairs(items) do
|
||||
TSM.guilds[TSM.CURRENT_GUILD].items[itemString] = quantity
|
||||
end
|
||||
|
||||
if GuildBankFrame and GuildBankFrame:IsVisible() then
|
||||
TSM.guilds[TSM.CURRENT_GUILD].lastUpdate = time()
|
||||
end
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
-- Ascension WoW: scan the personal bank (per character)
|
||||
function Data:GetPersonalBankData()
|
||||
-- Initialize personal bank for current player if needed
|
||||
if not TSM.personalBanks[TSM.CURRENT_PLAYER] then
|
||||
TSM.personalBanks[TSM.CURRENT_PLAYER] = { items = {}, lastUpdate = 0 }
|
||||
end
|
||||
wipe(TSM.personalBanks[TSM.CURRENT_PLAYER].items)
|
||||
|
||||
local items = ScanGuildBankSlots()
|
||||
for itemString, quantity in pairs(items) do
|
||||
TSM.personalBanks[TSM.CURRENT_PLAYER].items[itemString] = quantity
|
||||
end
|
||||
|
||||
TSM.personalBanks[TSM.CURRENT_PLAYER].lastUpdate = time()
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
-- Ascension WoW: scan the realm bank (shared across realm)
|
||||
function Data:GetRealmBankData()
|
||||
-- Initialize realm bank if needed
|
||||
if not TSM.realmBank.items then
|
||||
TSM.realmBank.items = {}
|
||||
end
|
||||
wipe(TSM.realmBank.items)
|
||||
|
||||
local items = ScanGuildBankSlots()
|
||||
for itemString, quantity in pairs(items) do
|
||||
TSM.realmBank.items[itemString] = quantity
|
||||
end
|
||||
|
||||
if GuildBankFrame and GuildBankFrame:IsVisible() then
|
||||
TSM.realmBank.lastUpdate = time()
|
||||
end
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
function Data:ScanPlayerAuctions()
|
||||
wipe(TSM.characters[TSM.CURRENT_PLAYER].auctions)
|
||||
TSM.characters[TSM.CURRENT_PLAYER].auctions.time = time()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_ItemTracker")
|
|||
|
||||
-- default values for the savedDB
|
||||
local savedDBDefaults = {
|
||||
-- any global
|
||||
-- any global
|
||||
global = {
|
||||
tooltip = "simple",
|
||||
},
|
||||
|
|
@ -23,6 +23,10 @@ local savedDBDefaults = {
|
|||
characters = {},
|
||||
guilds = {},
|
||||
ignoreGuilds = {},
|
||||
-- Ascension WoW: Personal banks (per character, stored by character name)
|
||||
personalBanks = {},
|
||||
-- Ascension WoW: Realm bank (shared across all characters on realm)
|
||||
realmBank = { items = {}, lastUpdate = 0 },
|
||||
},
|
||||
|
||||
-- data that is stored per user profile
|
||||
|
|
@ -47,6 +51,11 @@ local guildDefaults = {
|
|||
items = {},
|
||||
lastUpdate = 0,
|
||||
}
|
||||
-- Ascension WoW: Personal bank defaults (same structure as guild)
|
||||
local personalBankDefaults = {
|
||||
items = {},
|
||||
lastUpdate = 0,
|
||||
}
|
||||
|
||||
-- Called once the player has loaded into the game
|
||||
-- Anything that needs to be done in order to initialize the addon should go here
|
||||
|
|
@ -58,9 +67,12 @@ function TSM:OnInitialize()
|
|||
|
||||
-- load the saved variables table into TSM.db
|
||||
TSM.db = LibStub:GetLibrary("AceDB-3.0"):New("AscensionTSM_ItemTrackerDB", savedDBDefaults, true)
|
||||
|
||||
|
||||
TSM.characters = TSM.db.realm.characters
|
||||
TSM.guilds = TSM.db.realm.guilds
|
||||
-- Ascension WoW: Personal banks and realm bank
|
||||
TSM.personalBanks = TSM.db.realm.personalBanks
|
||||
TSM.realmBank = TSM.db.realm.realmBank
|
||||
|
||||
-- handle connected realms for characters
|
||||
local connectedRealms = TSMAPI.GetConnectedRealms and TSMAPI:GetConnectedRealms() or {}
|
||||
|
|
@ -117,6 +129,11 @@ function TSM:OnInitialize()
|
|||
for _, guildData in pairs(TSM.guilds) do
|
||||
ClearItemIDs(guildData.items)
|
||||
end
|
||||
-- Ascension WoW: Clean up personal banks and realm bank
|
||||
for _, personalBankData in pairs(TSM.personalBanks) do
|
||||
ClearItemIDs(personalBankData.items)
|
||||
end
|
||||
ClearItemIDs(TSM.realmBank.items)
|
||||
|
||||
TSM.Data:Initialize()
|
||||
TSM:UpdatePlayerLookup()
|
||||
|
|
@ -151,6 +168,11 @@ function TSM:RegisterModule()
|
|||
{ key = "guildtotal", callback = "GetGuildTotal" },
|
||||
{ key = "playerguildtotal", callback = "GetPlayerGuildTotal" },
|
||||
{ key = "playerguild", callback = "GetPlayerGuild" },
|
||||
-- Ascension WoW: Personal banks and realm bank APIs
|
||||
{ key = "personalbank", callback = "GetPersonalBank" },
|
||||
{ key = "realmbank", callback = "GetRealmBank" },
|
||||
{ key = "personalbankstotal", callback = "GetPersonalBanksTotal" },
|
||||
{ key = "realmbanktotal", callback = "GetRealmBankTotal" },
|
||||
}
|
||||
--TSM.sync = { callback = "Sync:Callback" }
|
||||
TSM.tooltipOptions = { callback = "Config:LoadTooltipOptions" }
|
||||
|
|
@ -169,9 +191,18 @@ function TSM:GetTooltip(itemString)
|
|||
local player, alts = TSM:GetPlayerTotal(itemString)
|
||||
local guild = TSM:GetGuildTotal(itemString)
|
||||
local auctions = TSM:GetAuctionsTotal(itemString)
|
||||
grandTotal = grandTotal + player + alts + guild + auctions
|
||||
-- Ascension WoW: Add personal banks and realm bank
|
||||
local personalBanks = TSM:GetPersonalBanksTotal(itemString)
|
||||
local realmBank = TSM:GetRealmBankTotal(itemString)
|
||||
grandTotal = grandTotal + player + alts + guild + auctions + personalBanks + realmBank
|
||||
if grandTotal > 0 then
|
||||
tinsert(text, { left = " " .. "ItemTracker:", right = format(L["(%s player, %s alts, %s guild banks, %s AH)"], "|cffffffff" .. player .. "|r", "|cffffffff" .. alts .. "|r", "|cffffffff" .. guild .. "|r", "|cffffffff" .. auctions .. "|r") })
|
||||
tinsert(text, { left = " " .. "ItemTracker:", right = format(L["(%s player, %s alts, %s guild, %s AH, %s personal, %s realm)"],
|
||||
"|cffffffff" .. player .. "|r",
|
||||
"|cffffffff" .. alts .. "|r",
|
||||
"|cffffffff" .. guild .. "|r",
|
||||
"|cffffffff" .. auctions .. "|r",
|
||||
"|cffffffff" .. personalBanks .. "|r",
|
||||
"|cffffffff" .. realmBank .. "|r") })
|
||||
end
|
||||
elseif TSM.db.global.tooltip == "full" then
|
||||
for name, data in pairs(TSM.characters) do
|
||||
|
|
@ -179,17 +210,26 @@ function TSM:GetTooltip(itemString)
|
|||
local bank = data.bank[itemString] or 0
|
||||
local auctions = data.auctions[itemString] or 0
|
||||
local mail = data.mail[itemString] or 0
|
||||
local total = bags + bank + auctions + mail
|
||||
-- Ascension WoW: Add personal bank for this character
|
||||
local personalBank = TSM.personalBanks[name] and TSM.personalBanks[name].items[itemString] or 0
|
||||
local total = bags + bank + auctions + mail + personalBank
|
||||
grandTotal = grandTotal + total
|
||||
|
||||
local bagText = "|cffffffff" .. bags .. "|r"
|
||||
local bankText = "|cffffffff" .. bank .. "|r"
|
||||
local auctionText = "|cffffffff" .. auctions .. "|r"
|
||||
local mailText = "|cffffffff" .. mail .. "|r"
|
||||
local personalBankText = "|cffffffff" .. personalBank .. "|r"
|
||||
local totalText = "|cffffffff" .. total .. "|r"
|
||||
|
||||
if total > 0 then
|
||||
tinsert(text, { left = format(" %s:", name), right = format(L["%s (%s bags, %s bank, %s AH, %s mail)"], "|cffffffff" .. totalText, "|cffffffff" .. bagText, "|cffffffff" .. bankText, "|cffffffff" .. auctionText, "|cffffffff" .. mailText) })
|
||||
tinsert(text, { left = format(" %s:", name), right = format(L["%s (%s bags, %s bank, %s AH, %s mail, %s personal)"],
|
||||
"|cffffffff" .. totalText,
|
||||
"|cffffffff" .. bagText,
|
||||
"|cffffffff" .. bankText,
|
||||
"|cffffffff" .. auctionText,
|
||||
"|cffffffff" .. mailText,
|
||||
"|cffffffff" .. personalBankText) })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -205,6 +245,14 @@ function TSM:GetTooltip(itemString)
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Ascension WoW: Show realm bank
|
||||
local realmBank = TSM:GetRealmBankTotal(itemString)
|
||||
if realmBank > 0 then
|
||||
grandTotal = grandTotal + realmBank
|
||||
local realmBankText = "|cffffffff" .. realmBank .. "|r"
|
||||
tinsert(text, { left = " " .. L["Realm Bank"] .. ":", right = format(L["%s in realm bank"], realmBankText) })
|
||||
end
|
||||
end
|
||||
|
||||
if #text > 0 then
|
||||
|
|
@ -343,4 +391,31 @@ function TSM:GetPlayerGuild(player)
|
|||
player = TSM.playerLookup[player] or player
|
||||
if not player or not TSM.characters[player] then return end
|
||||
return TSM.characters[player].guild
|
||||
end
|
||||
|
||||
-- Ascension WoW: Get personal bank data for a player
|
||||
function TSM:GetPersonalBank(player)
|
||||
player = player or TSM.CURRENT_PLAYER
|
||||
player = TSM.playerLookup[player] or player
|
||||
if not player or not TSM.personalBanks[player] then return end
|
||||
return TSM.personalBanks[player].items
|
||||
end
|
||||
|
||||
-- Ascension WoW: Get realm bank data
|
||||
function TSM:GetRealmBank()
|
||||
return TSM.realmBank.items
|
||||
end
|
||||
|
||||
-- Ascension WoW: Get total items across all personal banks
|
||||
function TSM:GetPersonalBanksTotal(itemString)
|
||||
local total = 0
|
||||
for _, data in pairs(TSM.personalBanks) do
|
||||
total = total + (data.items[itemString] or 0)
|
||||
end
|
||||
return total
|
||||
end
|
||||
|
||||
-- Ascension WoW: Get realm bank total for an item
|
||||
function TSM:GetRealmBankTotal(itemString)
|
||||
return TSM.realmBank.items[itemString] or 0
|
||||
end
|
||||
|
|
@ -59,7 +59,7 @@ end
|
|||
|
||||
-- registers this module with TSM by first setting all fields and then calling TSMAPI:NewModule().
|
||||
function TSM:RegisterModule()
|
||||
TSM.operations = {maxOperations=12, callbackOptions="Options:Load", callbackInfo="GetOperationInfo"}
|
||||
TSM.operations = {maxOperations=100, callbackOptions="Options:Load", callbackInfo="GetOperationInfo"}
|
||||
TSM.moduleAPIs = {
|
||||
{key="mailItems", callback="AutoMail:SendItems"},
|
||||
}
|
||||
|
|
@ -89,4 +89,4 @@ function TSM:GetOperationInfo(operationName)
|
|||
else
|
||||
return format(L["Mailing all to %s."], operation.target)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,10 +30,8 @@ modules\Options.lua
|
|||
|
||||
sidebar\Sidebar.lua
|
||||
sidebar\Saved.lua
|
||||
sidebar\Sniper.lua
|
||||
sidebar\Groups.lua
|
||||
sidebar\ShoppingLog.lua
|
||||
sidebar\QuickPosting.lua
|
||||
sidebar\CustomFilter.lua
|
||||
sidebar\Crafting.lua
|
||||
sidebar\Other.lua
|
||||
71
tools/build_zip.sh
Executable file
71
tools/build_zip.sh
Executable file
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env bash
|
||||
# Build per-addon zip artefacts from HEAD via git-archive.
|
||||
#
|
||||
# - Discovers top-level addon folders (Foo/Foo.toc).
|
||||
# - Re-creates dist/ each run.
|
||||
# - Always archives HEAD, so the working tree state is irrelevant.
|
||||
# - If more than one addon folder is present, also emits <repo>-all.zip
|
||||
# with every addon folder side-by-side at the zip root.
|
||||
# - When run inside Gitea Actions the working tree lives under a
|
||||
# per-job dir like /var/lib/act_runner/work/.../hostexecutor, so the
|
||||
# repo name comes from $GITHUB_REPOSITORY (set by the runner) and
|
||||
# only falls back to the toplevel basename for local invocations.
|
||||
set -euo pipefail
|
||||
|
||||
root=$(git rev-parse --show-toplevel)
|
||||
cd "$root"
|
||||
|
||||
# Gitea Actions sets GITHUB_REPOSITORY=owner/repo. The basename of
|
||||
# `git rev-parse --show-toplevel` inside the runner is the worker dir
|
||||
# (e.g. `hostexecutor`), which would name the bundle wrong.
|
||||
if [ -n "${GITHUB_REPOSITORY:-}" ]; then
|
||||
repo_name="${GITHUB_REPOSITORY##*/}"
|
||||
else
|
||||
repo_name=$(basename "$root")
|
||||
fi
|
||||
dist="$root/dist"
|
||||
|
||||
# Find Foo/Foo.toc pairs at depth 1; ignore libs nested deeper.
|
||||
addons=()
|
||||
while IFS= read -r toc; do
|
||||
dir=$(dirname "$toc")
|
||||
folder=$(basename "$dir")
|
||||
base=$(basename "$toc" .toc)
|
||||
# Accept Foo.toc and Foo_Wrath.toc style flavour variants; folder must match
|
||||
# at least one toc basename prefix (Foo).
|
||||
case "$base" in
|
||||
"$folder"|"$folder"_*) addons+=("$folder") ;;
|
||||
esac
|
||||
done < <(command find . -mindepth 2 -maxdepth 2 -type f -name '*.toc' | sed 's|^\./||' | sort)
|
||||
|
||||
# Dedupe (a folder with Foo.toc + Foo_Wrath.toc shows up twice).
|
||||
if [ ${#addons[@]} -gt 0 ]; then
|
||||
mapfile -t addons < <(printf '%s\n' "${addons[@]}" | awk '!seen[$0]++')
|
||||
fi
|
||||
|
||||
if [ ${#addons[@]} -eq 0 ]; then
|
||||
echo "no addon folders found (looking for */Foo.toc with matching folder name)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "$dist"
|
||||
mkdir -p "$dist"
|
||||
|
||||
for folder in "${addons[@]}"; do
|
||||
out="$dist/$folder.zip"
|
||||
# No --prefix: the folder already sits at the repo root, so git-archive
|
||||
# emits entries as <folder>/... which is exactly what
|
||||
# Interface/AddOns/ expects after extraction.
|
||||
git archive HEAD --format=zip -o "$out" -- "$folder"
|
||||
echo "built dist/$folder.zip"
|
||||
done
|
||||
|
||||
# Combined bundle only makes sense when there are multiple addons.
|
||||
if [ ${#addons[@]} -gt 1 ]; then
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
git archive HEAD --format=tar -- "${addons[@]}" | tar -x -C "$tmp"
|
||||
out="$dist/$repo_name-all.zip"
|
||||
( cd "$tmp" && zip -qr "$out" "${addons[@]}" )
|
||||
echo "built dist/$repo_name-all.zip"
|
||||
fi
|
||||
Loading…
Add table
Add a link
Reference in a new issue