Add tested modules and organize Extras categories
This commit is contained in:
@@ -39,12 +39,19 @@ Settings: **Esc → Advanced Options**.
|
||||
- Reagent Counter now uses ClassicAPI spell reagent and item count data instead of tooltip scanning.
|
||||
- Reveal World Map now uses live ClassicAPI map overlay data instead of bundled static map tables.
|
||||
- Better Turtle WoW-like server compatibility for items, auras and UI behavior.
|
||||
- Added Auction Alt-Buy and Buy Em All as optional merchant and auction conveniences.
|
||||
- Added modifier-aware Key-Down Casting with an independent Alt Self-Cast option.
|
||||
- Added Metric Range for metre labels in range tooltips without changing numeric values.
|
||||
- Various stability fixes across legacy ShaguTweaks Extras modules.
|
||||
|
||||
## 🔷 Mods using ClassicAPI integration
|
||||
|
||||
- Auction Alt-Buy
|
||||
- Bag Item Click
|
||||
- Bag Search Bar
|
||||
- Buy Em All
|
||||
- Key-Down Casting
|
||||
- Alt Self-Cast
|
||||
- Macro Icons
|
||||
- Macro Tweaks
|
||||
- Raid Frames
|
||||
@@ -66,6 +73,26 @@ Other modules can also benefit indirectly from ClassicAPI through shared ShaguTw
|
||||
- Reagent Counter
|
||||
- Show Bags
|
||||
- Show Micro Menu
|
||||
- Key-Down Casting
|
||||
- Alt Self-Cast
|
||||
|
||||
### Bags & Inventory
|
||||
|
||||
- Bag Item Click
|
||||
- Bag Search Bar
|
||||
|
||||
### Merchant & Auction
|
||||
|
||||
- Auction Alt-Buy
|
||||
- Buy Em All
|
||||
|
||||
### Tooltip & Items
|
||||
|
||||
- Metric Range
|
||||
|
||||
### World Map
|
||||
|
||||
- Reveal World Map
|
||||
|
||||
### Chat
|
||||
|
||||
@@ -73,12 +100,6 @@ Other modules can also benefit indirectly from ClassicAPI through shared ShaguTw
|
||||
- Center Text Input Box
|
||||
- Enable Text Shadow
|
||||
|
||||
### Bags & World Map
|
||||
|
||||
- Bag Item Click
|
||||
- Bag Search Bar
|
||||
- Reveal World Map
|
||||
|
||||
### Macro
|
||||
|
||||
- Macro Icons
|
||||
|
||||
+19
-7
@@ -18,17 +18,33 @@ locales\translations_zhTW.lua
|
||||
# core
|
||||
main.lua
|
||||
|
||||
# general
|
||||
mods\macro-icons.lua
|
||||
mods\macro-tweaks.lua
|
||||
# action bar
|
||||
mods\actionbar-df-gryphon.lua
|
||||
mods\actionbar-right-center.lua
|
||||
mods\actionbar-reagents.lua
|
||||
mods\actionbar-float.lua
|
||||
mods\classic-snowfall.lua
|
||||
mods\reduced-actionbar-bags.lua
|
||||
mods\reduced-actionbar-micromenu.lua
|
||||
|
||||
# bags & inventory
|
||||
mods\bag-item-click.lua
|
||||
mods\bag-search.lua
|
||||
|
||||
# merchant & auction
|
||||
mods\auction-alt-buy.lua
|
||||
mods\buy-em-all.lua
|
||||
|
||||
# tooltip & items
|
||||
mods\metric-range.lua
|
||||
|
||||
# world map
|
||||
mods\worldmap-reveal.lua
|
||||
|
||||
# macro
|
||||
mods\macro-icons.lua
|
||||
mods\macro-tweaks.lua
|
||||
|
||||
# chat
|
||||
mods\chat-input-center.lua
|
||||
mods\chat-text-shadow.lua
|
||||
@@ -44,7 +60,3 @@ mods\raid-aggro-indicator.lua
|
||||
mods\raid-healing-predictions.lua
|
||||
mods\raid-compact-layout.lua
|
||||
mods\raid-hide-party.lua
|
||||
|
||||
# reduced actionbar size
|
||||
mods\reduced-actionbar-bags.lua
|
||||
mods\reduced-actionbar-micromenu.lua
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
local T = ShaguTweaks.T
|
||||
local API = ShaguTweaks.API
|
||||
local hooksecurefunc = ShaguTweaks.hooksecurefunc
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Auction Alt-Buy"],
|
||||
description = T["Alt-click an auction to buy it out instantly, or Alt-click your own auction to cancel it."],
|
||||
expansions = { ["vanilla"] = true },
|
||||
category = T["Merchant & Auction"],
|
||||
enabled = true,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
-- Do not double-hook when migrating from the standalone addon.
|
||||
if IsAddOnLoaded("AuctionAltBuy") then return end
|
||||
|
||||
local installed
|
||||
|
||||
local function AltDown()
|
||||
return API and API.IsAltKeyDown and API.IsAltKeyDown()
|
||||
end
|
||||
|
||||
local function InstallHooks()
|
||||
if installed then return end
|
||||
if type(_G.BrowseButton_OnClick) ~= "function"
|
||||
or type(_G.AuctionsButton_OnClick) ~= "function" then
|
||||
return
|
||||
end
|
||||
|
||||
-- Run after the native handler so the clicked row has already become the
|
||||
-- selected auction. Read the selected row itself instead of trusting a
|
||||
-- cached frame-level buyout value.
|
||||
hooksecurefunc("BrowseButton_OnClick", function()
|
||||
if not AltDown() then return end
|
||||
if not AuctionFrame or not AuctionFrame.type then return end
|
||||
|
||||
local index = GetSelectedAuctionItem(AuctionFrame.type)
|
||||
if not index or index <= 0 then return end
|
||||
|
||||
local _, _, _, _, _, _, _, _, buyout = GetAuctionItemInfo(AuctionFrame.type, index)
|
||||
if buyout and buyout > 0 then
|
||||
PlaceAuctionBid(AuctionFrame.type, index, buyout)
|
||||
end
|
||||
end)
|
||||
|
||||
hooksecurefunc("AuctionsButton_OnClick", function()
|
||||
if not AltDown() then return end
|
||||
|
||||
local index = GetSelectedAuctionItem("owner")
|
||||
if index and index > 0 then
|
||||
CancelAuction(index)
|
||||
end
|
||||
end)
|
||||
|
||||
installed = true
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:RegisterEvent("AUCTION_HOUSE_SHOW")
|
||||
frame:SetScript("OnEvent", InstallHooks)
|
||||
|
||||
-- Some 1.12 clients keep auction functions resident.
|
||||
InstallHooks()
|
||||
end
|
||||
@@ -7,6 +7,7 @@ local module = ShaguTweaks:register({
|
||||
title = T["Bag Item Click"],
|
||||
description = T["Send items to trade window or auction house search via right click."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Bags & Inventory"],
|
||||
maintainer = "@shagu (GitHub)",
|
||||
enabled = true,
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ local module = ShaguTweaks:register({
|
||||
title = T["Bag Search Bar"],
|
||||
description = T["Adds a search field to the bag which allows you to search bag, keyring and bank slots."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Bags & Inventory"],
|
||||
maintainer = "@shagu (GitHub)",
|
||||
enabled = true,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,662 @@
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
local T = ShaguTweaks.T
|
||||
local API = ShaguTweaks.API
|
||||
local HookScript = ShaguTweaks.HookScript
|
||||
local floor = math.floor
|
||||
local ceil = math.ceil
|
||||
local min = math.min
|
||||
local mod = math.mod or mod
|
||||
|
||||
STBuyEmAll = STBuyEmAll or {}
|
||||
local Buy = STBuyEmAll
|
||||
|
||||
local strings = {
|
||||
enUS = {
|
||||
["Max"] = "Max",
|
||||
["Stack"] = "Stack",
|
||||
["Are you sure you want to buy\n %d × %s?"] = "Are you sure you want to buy\n %d × %s?",
|
||||
["Stack purchase"] = "Stack purchase",
|
||||
["Stack size"] = "Stack size",
|
||||
["Partial stack"] = "Partial stack",
|
||||
["Maximum purchase"] = "Maximum purchase",
|
||||
["You can fit"] = "You can fit",
|
||||
["You can afford"] = "You can afford",
|
||||
["Vendor has"] = "Vendor has",
|
||||
},
|
||||
deDE = {
|
||||
["Are you sure you want to buy\n %d × %s?"] = "Bist du sicher das du\n %d × %s kaufen willst?",
|
||||
["Stack size"] = "Stack größe",
|
||||
["Maximum purchase"] = "Größt möglicher Einkauf",
|
||||
["You can fit"] = "Du hast Platz für",
|
||||
["You can afford"] = "Du kannst dir leisten",
|
||||
["Vendor has"] = "Der Verkäufer hat",
|
||||
},
|
||||
frFR = {
|
||||
["Stack"] = "Pile",
|
||||
["Are you sure you want to buy\n %d × %s?"] = "Voulez-vous vraiment acheter\n %d × %s?",
|
||||
["Stack size"] = "Taille de pile",
|
||||
["Maximum purchase"] = "Achat maximum",
|
||||
["You can fit"] = "Vous pouvez transporter",
|
||||
["You can afford"] = "Vous pouvez payer",
|
||||
["Vendor has"] = "Le marchand a",
|
||||
},
|
||||
}
|
||||
|
||||
local locale = strings[GetLocale()] or strings.enUS
|
||||
local function L(key)
|
||||
return locale[key] or strings.enUS[key] or key
|
||||
end
|
||||
|
||||
BUYEMALL_MAX = L("Max")
|
||||
BUYEMALL_STACK = L("Stack")
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Buy Em All"],
|
||||
description = T["Shift-click vendor items to choose stack, maximum, or a custom purchase amount."],
|
||||
expansions = { ["vanilla"] = true },
|
||||
category = T["Merchant & Auction"],
|
||||
enabled = true,
|
||||
})
|
||||
|
||||
local function FamilyMatches(itemFamily, bagFamily)
|
||||
bagFamily = tonumber(bagFamily) or 0
|
||||
itemFamily = tonumber(itemFamily) or 0
|
||||
|
||||
if bagFamily == 0 then return true end
|
||||
if itemFamily == 0 then return false end
|
||||
|
||||
-- Bag families are power-of-two bit flags. Avoid requiring an external bit
|
||||
-- library on 1.12 while still supporting Turtle custom specialty families.
|
||||
return mod(floor(itemFamily / bagFamily), 2) == 1
|
||||
end
|
||||
|
||||
function Buy:CountPurchaseItem()
|
||||
if not self.purchaseItemID then return nil end
|
||||
if API and API.GetItemCount then
|
||||
return API.GetItemCount(self.purchaseItemID, false, false)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function Buy:StopPurchaseQueue()
|
||||
if self.purchaseFrame then self.purchaseFrame:Hide() end
|
||||
self.purchaseItemIndex = nil
|
||||
self.purchaseItemID = nil
|
||||
self.purchasePreset = 1
|
||||
self.purchaseLoops = 0
|
||||
self.purchaseAmount = 0
|
||||
self.purchaseLeftover = 0
|
||||
self.purchaseElapsed = 0
|
||||
self.purchaseWaiting = nil
|
||||
self.purchaseExpectedCount = nil
|
||||
self.purchasePendingKind = nil
|
||||
end
|
||||
|
||||
function Buy:AbortPurchaseQueue()
|
||||
self:StopPurchaseQueue()
|
||||
DEFAULT_CHAT_FRAME:AddMessage("Buy Em All: purchase queue stopped because the previous stack was not confirmed. No further stacks were sent.")
|
||||
end
|
||||
|
||||
function Buy:ConfirmPendingPurchase()
|
||||
if not self.purchaseWaiting or not self.purchaseExpectedCount then return false end
|
||||
|
||||
local count = self:CountPurchaseItem()
|
||||
if count == nil or count < self.purchaseExpectedCount then return false end
|
||||
|
||||
if self.purchasePendingKind == "loop" then
|
||||
self.purchaseLoops = self.purchaseLoops - 1
|
||||
elseif self.purchasePendingKind == "leftover" then
|
||||
self.purchaseLeftover = 0
|
||||
end
|
||||
|
||||
self.purchaseWaiting = nil
|
||||
self.purchaseExpectedCount = nil
|
||||
self.purchasePendingKind = nil
|
||||
self.purchaseElapsed = 0
|
||||
return true
|
||||
end
|
||||
|
||||
function Buy:Purchase_OnEvent()
|
||||
self:ConfirmPendingPurchase()
|
||||
end
|
||||
|
||||
function Buy:SendPurchase(quantity, kind)
|
||||
local before = self:CountPurchaseItem()
|
||||
if before == nil then
|
||||
self:AbortPurchaseQueue()
|
||||
return
|
||||
end
|
||||
|
||||
self.purchaseWaiting = true
|
||||
self.purchasePendingKind = kind
|
||||
self.purchaseExpectedCount = before + quantity * (self.purchasePreset or 1)
|
||||
self.purchaseElapsed = 0
|
||||
BuyMerchantItem(self.purchaseItemIndex, quantity)
|
||||
end
|
||||
|
||||
function Buy:Purchase_OnUpdate(elapsed)
|
||||
self.purchaseElapsed = (self.purchaseElapsed or 0) + (elapsed or 0)
|
||||
|
||||
if self.purchaseWaiting then
|
||||
if self.purchaseElapsed >= self.purchaseTimeout then
|
||||
if not self:ConfirmPendingPurchase() then self:AbortPurchaseQueue() end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if self.purchaseElapsed < self.purchaseDelay then return end
|
||||
self.purchaseElapsed = 0
|
||||
|
||||
if self.purchaseLoops and self.purchaseLoops > 0 then
|
||||
self:SendPurchase(self.purchaseAmount, "loop")
|
||||
return
|
||||
end
|
||||
|
||||
if self.purchaseLeftover and self.purchaseLeftover > 0 then
|
||||
self:SendPurchase(self.purchaseLeftover, "leftover")
|
||||
return
|
||||
end
|
||||
|
||||
self:StopPurchaseQueue()
|
||||
end
|
||||
|
||||
function Buy:DoPurchase(amount)
|
||||
if not amount or amount <= 0 or not self.itemIndex or not self.preset or not self.stack then return end
|
||||
if STBuyEmAllFrame then STBuyEmAllFrame:Hide() end
|
||||
|
||||
local numLoops, purchaseAmount, leftover
|
||||
if self.preset > 1 then
|
||||
numLoops = floor(amount / self.preset)
|
||||
purchaseAmount = 1
|
||||
leftover = 0
|
||||
else
|
||||
numLoops = floor(amount / self.stack)
|
||||
purchaseAmount = self.stack
|
||||
leftover = mod(amount, self.stack)
|
||||
end
|
||||
|
||||
self:StopPurchaseQueue()
|
||||
self.purchaseItemIndex = self.itemIndex
|
||||
self.purchaseItemID = self.itemID
|
||||
self.purchasePreset = self.preset
|
||||
self.purchaseLoops = numLoops
|
||||
self.purchaseAmount = purchaseAmount
|
||||
self.purchaseLeftover = leftover
|
||||
self.purchaseElapsed = self.purchaseDelay
|
||||
|
||||
if self.purchaseLoops > 0 or self.purchaseLeftover > 0 then
|
||||
self.purchaseFrame:Show()
|
||||
end
|
||||
end
|
||||
|
||||
function Buy:DoConfirmation(amount)
|
||||
self.confirmAmount = amount
|
||||
local dialog = StaticPopup_Show("STBUYEMALL_CONFIRM", amount, self.itemName)
|
||||
if dialog then dialog.data = amount end
|
||||
end
|
||||
|
||||
function Buy:VerifyPurchase(amount)
|
||||
amount = amount or self.split
|
||||
if not amount or amount <= 0 or not self.preset or self.preset <= 0 then return end
|
||||
|
||||
amount = ceil(amount / self.preset) * self.preset
|
||||
if amount > self.max then amount = self.max end
|
||||
|
||||
if amount > self.stack and amount > self.defaultStack then
|
||||
self:DoConfirmation(amount)
|
||||
else
|
||||
self:DoPurchase(amount)
|
||||
end
|
||||
end
|
||||
|
||||
function Buy:SetStackClick()
|
||||
if not self.stack or self.stack <= 0 then
|
||||
self.stackClick = self.max or self.split or 1
|
||||
return
|
||||
end
|
||||
|
||||
local targetRemainder = self.partialFit or 0
|
||||
if targetRemainder == 0 then targetRemainder = self.stack end
|
||||
|
||||
local currentRemainder = mod(self.split, self.stack)
|
||||
local increase = targetRemainder - currentRemainder
|
||||
if increase <= 0 then increase = increase + self.stack end
|
||||
|
||||
self.stackClick = self.split + increase
|
||||
end
|
||||
|
||||
function Buy:UpdateDisplay(amount)
|
||||
if not self.preset or not self.price or not self.split then return end
|
||||
|
||||
local purchase = ceil((amount or self.split) / self.preset)
|
||||
local cost = purchase * self.price
|
||||
if STBuyEmAllMoneyFrame then
|
||||
MoneyFrame_Update("STBuyEmAllMoneyFrame", cost)
|
||||
end
|
||||
|
||||
if not amount and not self.isUpdating then
|
||||
self.isUpdating = true
|
||||
|
||||
STBuyEmAllText:SetText(self.split)
|
||||
STBuyEmAllLeftButton:Enable()
|
||||
STBuyEmAllRightButton:Enable()
|
||||
|
||||
if self.split >= self.max then
|
||||
STBuyEmAllRightButton:Disable()
|
||||
elseif self.split <= self.preset then
|
||||
STBuyEmAllLeftButton:Disable()
|
||||
end
|
||||
|
||||
self:SetStackClick()
|
||||
STBuyEmAllStackButton:Enable()
|
||||
if not self.stackClick or self.max < self.stackClick then
|
||||
STBuyEmAllStackButton:Disable()
|
||||
end
|
||||
|
||||
self.isUpdating = nil
|
||||
end
|
||||
end
|
||||
|
||||
function Buy:Show(anchor)
|
||||
self.typing = 0
|
||||
STBuyEmAllLeftButton:Disable()
|
||||
STBuyEmAllRightButton:Enable()
|
||||
|
||||
self:SetStackClick()
|
||||
STBuyEmAllStackButton:Enable()
|
||||
if not self.stackClick or self.max < self.stackClick then STBuyEmAllStackButton:Disable() end
|
||||
|
||||
STBuyEmAllFrame:ClearAllPoints()
|
||||
STBuyEmAllFrame:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", 0, 4)
|
||||
STBuyEmAllFrame:Show()
|
||||
self:UpdateDisplay()
|
||||
end
|
||||
|
||||
function Buy:OnClick()
|
||||
if this == STBuyEmAllOkayButton then
|
||||
self:VerifyPurchase()
|
||||
elseif this == STBuyEmAllCancelButton then
|
||||
STBuyEmAllFrame:Hide()
|
||||
elseif this == STBuyEmAllStackButton then
|
||||
if self.stackClick and self.stackClick <= self.max then
|
||||
self.split = self.stackClick
|
||||
self:UpdateDisplay()
|
||||
if this:IsEnabled() == 1 then self:OnEnter() else GameTooltip:Hide() end
|
||||
end
|
||||
elseif this == STBuyEmAllMaxButton then
|
||||
self.split = self.max
|
||||
self:UpdateDisplay()
|
||||
end
|
||||
end
|
||||
|
||||
function Buy:OnChar()
|
||||
local digit = tonumber(arg1)
|
||||
if digit == nil then return end
|
||||
|
||||
if self.typing == 0 then
|
||||
self.typing = 1
|
||||
self.split = 0
|
||||
end
|
||||
|
||||
local split = (self.split * 10) + digit
|
||||
if split <= self.max then
|
||||
self.split = split
|
||||
end
|
||||
|
||||
if self.split <= 0 then self.split = 1 end
|
||||
self:UpdateDisplay()
|
||||
end
|
||||
|
||||
function Buy:OnKeyDown()
|
||||
if arg1 == "BACKSPACE" or arg1 == "DELETE" then
|
||||
if self.typing == 0 or self.split == 1 then return end
|
||||
|
||||
self.split = floor(self.split / 10)
|
||||
if self.split <= 1 then
|
||||
self.split = 1
|
||||
self.typing = 0
|
||||
end
|
||||
self:UpdateDisplay()
|
||||
elseif arg1 == "ENTER" then
|
||||
self:VerifyPurchase()
|
||||
elseif arg1 == "ESCAPE" then
|
||||
STBuyEmAllFrame:Hide()
|
||||
elseif arg1 == "LEFT" or arg1 == "DOWN" then
|
||||
self:Left_Click()
|
||||
elseif arg1 == "RIGHT" or arg1 == "UP" then
|
||||
self:Right_Click()
|
||||
end
|
||||
end
|
||||
|
||||
function Buy:Left_Click()
|
||||
if self.split <= self.preset then return end
|
||||
|
||||
local decrease = mod(self.split, self.preset)
|
||||
decrease = decrease == 0 and self.preset or decrease
|
||||
self.split = self.split - decrease
|
||||
self:UpdateDisplay()
|
||||
end
|
||||
|
||||
function Buy:Right_Click()
|
||||
local increase = self.preset - mod(self.split, self.preset)
|
||||
if self.split + increase > self.max then return end
|
||||
|
||||
self.split = self.split + increase
|
||||
self:UpdateDisplay()
|
||||
end
|
||||
|
||||
Buy.lines = {
|
||||
stack = {
|
||||
label = L("Stack purchase"),
|
||||
field = "stackClick",
|
||||
{ label = L("Stack size"), field = "stack" },
|
||||
{ label = L("Partial stack"), field = "partialFit" },
|
||||
},
|
||||
max = {
|
||||
label = L("Maximum purchase"),
|
||||
field = "max",
|
||||
{ label = L("You can fit"), field = "fit" },
|
||||
{ label = L("You can afford"), field = "afford" },
|
||||
{
|
||||
label = L("Vendor has"),
|
||||
field = "available",
|
||||
Hide = function()
|
||||
return not Buy.available or Buy.available <= 1
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
function Buy:CreateTooltip(lines)
|
||||
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT")
|
||||
GameTooltip:SetText(lines.label .. "|cFFFFFFFF - |r" .. GREEN_FONT_COLOR_CODE .. (lines.amount or 0) .. "|r")
|
||||
|
||||
for _, line in ipairs(lines) do
|
||||
if not (line.Hide and line.Hide()) then
|
||||
local color = line.amount == lines.amount and GREEN_FONT_COLOR or HIGHLIGHT_FONT_COLOR
|
||||
GameTooltip:AddDoubleLine(line.label, line.amount or 0, 1, 1, 1, color.r, color.g, color.b)
|
||||
end
|
||||
end
|
||||
|
||||
GameTooltip:Show()
|
||||
end
|
||||
|
||||
function Buy:OnEnter()
|
||||
local lines = self.lines[this == STBuyEmAllMaxButton and "max" or "stack"]
|
||||
lines.amount = self[lines.field]
|
||||
for _, line in ipairs(lines) do line.amount = self[line.field] end
|
||||
|
||||
self:CreateTooltip(lines)
|
||||
self:UpdateDisplay(lines.amount)
|
||||
end
|
||||
|
||||
function Buy:OnLeave()
|
||||
self:UpdateDisplay()
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
|
||||
function Buy:OnHide()
|
||||
StaticPopup_Hide("STBUYEMALL_CONFIRM")
|
||||
end
|
||||
|
||||
function Buy:FreeBagSpace(itemID)
|
||||
if not itemID then return 0, 1 end
|
||||
|
||||
local stackSize = API.GetItemMaxStackSizeByID(itemID) or 1
|
||||
if stackSize < 1 then stackSize = 1 end
|
||||
|
||||
local itemFamily = API.GetItemFamily(itemID) or 0
|
||||
local capacity = 0
|
||||
|
||||
for bag = 0, 4 do
|
||||
local freeSlots, bagFamily = API.GetContainerNumFreeSlots(bag)
|
||||
if FamilyMatches(itemFamily, bagFamily) then
|
||||
capacity = capacity + (freeSlots or 0) * stackSize
|
||||
end
|
||||
|
||||
local numSlots = GetContainerNumSlots(bag)
|
||||
for slot = 1, numSlots do
|
||||
local bagItemID = API.GetContainerItemID(bag, slot)
|
||||
if bagItemID == itemID then
|
||||
local itemCount = API.GetContainerItemStackCount(bag, slot) or 0
|
||||
if itemCount < stackSize then
|
||||
capacity = capacity + stackSize - itemCount
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return capacity, stackSize
|
||||
end
|
||||
|
||||
function Buy:GetMerchantData(index)
|
||||
local info = API.GetMerchantItemInfo and API.GetMerchantItemInfo(index)
|
||||
if info and info.itemID then
|
||||
local name = API.GetItemNameByID(info.itemID)
|
||||
if not name then
|
||||
name = GetMerchantItemInfo(index)
|
||||
end
|
||||
|
||||
return name, info.itemID, info.price or 0, info.stackCount or 1,
|
||||
info.numAvailable or -1
|
||||
end
|
||||
|
||||
local name, _, price, quantity, numAvailable = GetMerchantItemInfo(index)
|
||||
local itemID = API.GetMerchantItemID and API.GetMerchantItemID(index)
|
||||
return name, itemID, price, quantity, numAvailable
|
||||
end
|
||||
|
||||
function Buy:HandleMerchantClick(anchor, button, ignoreModifiers)
|
||||
if not anchor or not anchor.GetID then return false end
|
||||
|
||||
if MerchantFrame.selectedTab ~= 1
|
||||
or not API.IsShiftKeyDown()
|
||||
or API.IsControlKeyDown()
|
||||
or ignoreModifiers
|
||||
or (ChatFrameEditBox:IsVisible() and button == "LeftButton") then
|
||||
return false
|
||||
end
|
||||
|
||||
self.itemIndex = anchor:GetID()
|
||||
local name, itemID, price, quantity, numAvailable = self:GetMerchantData(self.itemIndex)
|
||||
if not name or not itemID or not price or not quantity or quantity < 1 then return false end
|
||||
|
||||
self.preset = quantity
|
||||
self.price = price
|
||||
self.itemName = name
|
||||
self.itemID = itemID
|
||||
self.available = numAvailable
|
||||
|
||||
local bagCapacity, stack = self:FreeBagSpace(itemID)
|
||||
self.stack = stack
|
||||
self.fit = floor(bagCapacity / quantity) * quantity
|
||||
|
||||
if price > 0 then
|
||||
self.afford = floor(GetMoney() / price) * quantity
|
||||
else
|
||||
self.afford = self.fit
|
||||
end
|
||||
|
||||
self.max = min(self.fit, self.afford)
|
||||
if numAvailable and numAvailable > -1 then
|
||||
self.max = min(self.max, numAvailable * quantity)
|
||||
end
|
||||
|
||||
if self.max <= 0 then return true end
|
||||
if self.max == 1 then
|
||||
if self.originalMerchantItemButton_OnClick then
|
||||
self.originalMerchantItemButton_OnClick("LeftButton", 1)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
self.defaultStack = quantity
|
||||
if self.defaultStack > self.max then self.defaultStack = self.max end
|
||||
|
||||
self.split = self.defaultStack
|
||||
self.partialFit = mod(self.fit, stack)
|
||||
self:SetStackClick()
|
||||
self:Show(anchor)
|
||||
return true
|
||||
end
|
||||
|
||||
function Buy:CreateUI()
|
||||
if STBuyEmAllFrame then return end
|
||||
|
||||
local frame = CreateFrame("Frame", "STBuyEmAllFrame", MerchantFrame)
|
||||
frame:SetWidth(210)
|
||||
frame:SetHeight(110)
|
||||
frame:SetFrameStrata("DIALOG")
|
||||
frame:SetBackdrop({
|
||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 8, edgeSize = 16,
|
||||
insets = { left = 4, right = 4, top = 4, bottom = 4 },
|
||||
})
|
||||
frame:SetBackdropColor(0, 0, 0, .9)
|
||||
frame:EnableKeyboard(true)
|
||||
frame:SetScript("OnChar", function() Buy:OnChar() end)
|
||||
frame:SetScript("OnKeyDown", function() Buy:OnKeyDown() end)
|
||||
frame:SetScript("OnHide", function() Buy:OnHide() end)
|
||||
frame:Hide()
|
||||
|
||||
local title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
title:SetPoint("TOP", frame, "TOP", 0, -10)
|
||||
title:SetText(T["Buy Em All"])
|
||||
|
||||
local amount = frame:CreateFontString("STBuyEmAllText", "ARTWORK", "GameFontHighlight")
|
||||
amount:SetWidth(50)
|
||||
amount:SetPoint("TOP", frame, "TOP", 0, -29)
|
||||
amount:SetText("1")
|
||||
|
||||
local left = CreateFrame("Button", "STBuyEmAllLeftButton", frame, "UIPanelButtonTemplate")
|
||||
left:SetWidth(28)
|
||||
left:SetHeight(22)
|
||||
left:SetPoint("RIGHT", amount, "LEFT", -4, 0)
|
||||
left:SetText("-")
|
||||
left:SetScript("OnClick", function() Buy:Left_Click() end)
|
||||
|
||||
local right = CreateFrame("Button", "STBuyEmAllRightButton", frame, "UIPanelButtonTemplate")
|
||||
right:SetWidth(28)
|
||||
right:SetHeight(22)
|
||||
right:SetPoint("LEFT", amount, "RIGHT", 4, 0)
|
||||
right:SetText("+")
|
||||
right:SetScript("OnClick", function() Buy:Right_Click() end)
|
||||
|
||||
local stack = CreateFrame("Button", "STBuyEmAllStackButton", frame, "UIPanelButtonTemplate")
|
||||
stack:SetWidth(58)
|
||||
stack:SetHeight(22)
|
||||
stack:SetPoint("TOPLEFT", frame, "TOPLEFT", 12, -50)
|
||||
stack:SetText(BUYEMALL_STACK)
|
||||
stack:SetScript("OnClick", function() Buy:OnClick() end)
|
||||
stack:SetScript("OnEnter", function() Buy:OnEnter() end)
|
||||
stack:SetScript("OnLeave", function() Buy:OnLeave() end)
|
||||
|
||||
local maxButton = CreateFrame("Button", "STBuyEmAllMaxButton", frame, "UIPanelButtonTemplate")
|
||||
maxButton:SetWidth(58)
|
||||
maxButton:SetHeight(22)
|
||||
maxButton:SetPoint("LEFT", stack, "RIGHT", 4, 0)
|
||||
maxButton:SetText(BUYEMALL_MAX)
|
||||
maxButton:SetScript("OnClick", function() Buy:OnClick() end)
|
||||
maxButton:SetScript("OnEnter", function() Buy:OnEnter() end)
|
||||
maxButton:SetScript("OnLeave", function() Buy:OnLeave() end)
|
||||
|
||||
local okay = CreateFrame("Button", "STBuyEmAllOkayButton", frame, "UIPanelButtonTemplate")
|
||||
okay:SetWidth(58)
|
||||
okay:SetHeight(22)
|
||||
okay:SetPoint("LEFT", maxButton, "RIGHT", 4, 0)
|
||||
okay:SetText(OKAY)
|
||||
okay:SetScript("OnClick", function() Buy:OnClick() end)
|
||||
|
||||
local cancel = CreateFrame("Button", "STBuyEmAllCancelButton", frame, "UIPanelButtonTemplate")
|
||||
cancel:SetWidth(58)
|
||||
cancel:SetHeight(22)
|
||||
cancel:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, -78)
|
||||
cancel:SetText(CANCEL)
|
||||
cancel:SetScript("OnClick", function() Buy:OnClick() end)
|
||||
|
||||
local money = CreateFrame("Frame", "STBuyEmAllMoneyFrame", frame, "SmallMoneyFrameTemplate")
|
||||
money:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 12, 11)
|
||||
|
||||
MoneyTypeInfo["STBUYEMALL"] = {
|
||||
UpdateFunc = function() return 0 end,
|
||||
showSmallerCoins = "Backpack",
|
||||
fixedWidth = 1,
|
||||
collapse = 1,
|
||||
}
|
||||
money.info = MoneyTypeInfo["STBUYEMALL"]
|
||||
money.moneyType = "STBUYEMALL"
|
||||
money.small = 1
|
||||
end
|
||||
|
||||
module.enable = function(self)
|
||||
if IsAddOnLoaded("BuyEmAll") then return end
|
||||
|
||||
local required = {
|
||||
"GetItemCount", "GetItemMaxStackSizeByID", "GetItemFamily",
|
||||
"GetContainerNumFreeSlots", "GetContainerItemID",
|
||||
"GetContainerItemStackCount", "GetMerchantItemInfo",
|
||||
"GetMerchantItemID", "IsShiftKeyDown", "IsControlKeyDown",
|
||||
}
|
||||
for _, name in ipairs(required) do
|
||||
if not API or type(API[name]) ~= "function" then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff5555ShaguTweaks Extras:|r Buy Em All requires the current ShaguTweaks-ClassicAPI.")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
Buy:CreateUI()
|
||||
|
||||
Buy.purchaseDelay = 0.05
|
||||
Buy.purchaseTimeout = 3.0
|
||||
Buy.purchaseFrame = Buy.purchaseFrame or CreateFrame("Frame", "STBuyEmAllPurchaseQueue", UIParent)
|
||||
Buy.purchaseFrame:Hide()
|
||||
Buy.purchaseFrame:RegisterEvent("BAG_UPDATE")
|
||||
Buy.purchaseFrame:RegisterEvent("MERCHANT_UPDATE")
|
||||
Buy.purchaseFrame:SetScript("OnEvent", function()
|
||||
Buy:Purchase_OnEvent()
|
||||
end)
|
||||
Buy.purchaseFrame:SetScript("OnUpdate", function()
|
||||
Buy:Purchase_OnUpdate(arg1)
|
||||
end)
|
||||
|
||||
StaticPopupDialogs["STBUYEMALL_CONFIRM"] = {
|
||||
text = L("Are you sure you want to buy\n %d × %s?"),
|
||||
button1 = YES,
|
||||
button2 = NO,
|
||||
OnAccept = function()
|
||||
Buy:DoPurchase(Buy.confirmAmount)
|
||||
end,
|
||||
timeout = 0,
|
||||
hideOnEscape = true,
|
||||
}
|
||||
|
||||
HookScript(MerchantFrame, "OnHide", function()
|
||||
STBuyEmAllFrame:Hide()
|
||||
Buy:StopPurchaseQueue()
|
||||
end)
|
||||
|
||||
local function MerchantItemButton_OnClick_Wrapper(button, ignoreModifiers)
|
||||
local anchor = this
|
||||
if Buy:HandleMerchantClick(anchor, button, ignoreModifiers) then return end
|
||||
if Buy.originalMerchantItemButton_OnClick then
|
||||
return Buy.originalMerchantItemButton_OnClick(button, ignoreModifiers)
|
||||
end
|
||||
end
|
||||
|
||||
local function InstallHook()
|
||||
local current = _G.MerchantItemButton_OnClick
|
||||
if type(current) ~= "function" then return end
|
||||
if current == MerchantItemButton_OnClick_Wrapper then return end
|
||||
|
||||
Buy.originalMerchantItemButton_OnClick = current
|
||||
_G.MerchantItemButton_OnClick = MerchantItemButton_OnClick_Wrapper
|
||||
end
|
||||
|
||||
InstallHook()
|
||||
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
frame:RegisterEvent("MERCHANT_SHOW")
|
||||
frame:SetScript("OnEvent", InstallHook)
|
||||
end
|
||||
@@ -0,0 +1,295 @@
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
local T = ShaguTweaks.T
|
||||
local API = ShaguTweaks.API
|
||||
|
||||
local selfcastTitle = T["Alt Self-Cast"]
|
||||
|
||||
local selfcast = ShaguTweaks:register({
|
||||
title = selfcastTitle,
|
||||
description = T["When Key-Down Casting is enabled, hold Alt to cast eligible actions on yourself."],
|
||||
expansions = { ["vanilla"] = true },
|
||||
category = T["Action Bar"],
|
||||
enabled = nil,
|
||||
})
|
||||
|
||||
selfcast.enable = function(self)
|
||||
-- Runtime behavior is handled by Key-Down Casting below.
|
||||
end
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Key-Down Casting"],
|
||||
description = T["Activates action-bar and pet actions when the key is pressed instead of when it is released."],
|
||||
expansions = { ["vanilla"] = true },
|
||||
category = T["Action Bar"],
|
||||
enabled = true,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
-- Keep this feature independent from No Toggle Auto-Attack.
|
||||
if IsAddOnLoaded("ClassicSnowFall") or IsAddOnLoaded("ClassicSnowfall") then return end
|
||||
|
||||
local function SelfCast()
|
||||
if ShaguTweaks_config and ShaguTweaks_config[selfcastTitle] == 1 then
|
||||
return API.IsAltKeyDown() and 1 or 0
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Preserve the original slash command while using a unique registry key.
|
||||
SLASH_STCLASSICSNOWFALLSELFCAST1 = "/csselfcast"
|
||||
SlashCmdList["STCLASSICSNOWFALLSELFCAST"] = function()
|
||||
ShaguTweaks_config = ShaguTweaks_config or {}
|
||||
if ShaguTweaks_config[selfcastTitle] == 1 then
|
||||
ShaguTweaks_config[selfcastTitle] = 0
|
||||
DEFAULT_CHAT_FRAME:AddMessage("Classic Snowfall ALT SelfCast now disabled.")
|
||||
else
|
||||
ShaguTweaks_config[selfcastTitle] = 1
|
||||
DEFAULT_CHAT_FRAME:AddMessage("Classic Snowfall ALT SelfCast now enabled.")
|
||||
end
|
||||
end
|
||||
|
||||
local function IsBongosReady()
|
||||
return _G.BActionButton and type(_G.BActionButton.GetPagedID) == "function"
|
||||
end
|
||||
|
||||
local function ST_ActionButtonDown(id)
|
||||
local button, pagedID
|
||||
|
||||
if IsBongosReady() then
|
||||
button = _G["BActionButton" .. id]
|
||||
pagedID = _G.BActionButton.GetPagedID(id)
|
||||
if button and button:GetButtonState() == "NORMAL" then
|
||||
button:SetButtonState("PUSHED")
|
||||
end
|
||||
if pagedID then UseAction(pagedID, 0, SelfCast()) end
|
||||
return
|
||||
end
|
||||
|
||||
if BonusActionBarFrame and BonusActionBarFrame:IsShown() then
|
||||
button = _G["BonusActionButton" .. id]
|
||||
else
|
||||
button = _G["ActionButton" .. id]
|
||||
end
|
||||
|
||||
if button and button:GetButtonState() == "NORMAL" then
|
||||
button:SetButtonState("PUSHED")
|
||||
UseAction(ActionButton_GetPagedID(button), 0, SelfCast())
|
||||
end
|
||||
end
|
||||
|
||||
local function ST_ActionButtonUp(id)
|
||||
local button, pagedID
|
||||
|
||||
if IsBongosReady() then
|
||||
button = _G["BActionButton" .. id]
|
||||
pagedID = _G.BActionButton.GetPagedID(id)
|
||||
if button and button:GetButtonState() == "PUSHED" then
|
||||
button:SetButtonState("NORMAL")
|
||||
if MacroFrame_SaveMacro then MacroFrame_SaveMacro() end
|
||||
if pagedID and IsCurrentAction(pagedID) then
|
||||
button:SetChecked(1)
|
||||
else
|
||||
button:SetChecked(0)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if BonusActionBarFrame and BonusActionBarFrame:IsShown() then
|
||||
button = _G["BonusActionButton" .. id]
|
||||
else
|
||||
button = _G["ActionButton" .. id]
|
||||
end
|
||||
|
||||
if button and button:GetButtonState() == "PUSHED" then
|
||||
button:SetButtonState("NORMAL")
|
||||
if MacroFrame_SaveMacro then MacroFrame_SaveMacro() end
|
||||
if IsCurrentAction(ActionButton_GetPagedID(button)) then
|
||||
button:SetChecked(1)
|
||||
else
|
||||
button:SetChecked(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ST_MultiActionButtonDown(bar, id)
|
||||
local button = _G[bar .. "Button" .. id]
|
||||
if button and button:GetButtonState() == "NORMAL" then
|
||||
button:SetButtonState("PUSHED")
|
||||
UseAction(ActionButton_GetPagedID(button), 0, SelfCast())
|
||||
end
|
||||
end
|
||||
|
||||
local function ST_MultiActionButtonUp(bar, id)
|
||||
local button = _G[bar .. "Button" .. id]
|
||||
if button and button:GetButtonState() == "PUSHED" then
|
||||
button:SetButtonState("NORMAL")
|
||||
if MacroFrame_SaveMacro then MacroFrame_SaveMacro() end
|
||||
if IsCurrentAction(ActionButton_GetPagedID(button)) then
|
||||
button:SetChecked(1)
|
||||
else
|
||||
button:SetChecked(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ST_PetActionButtonDown(id)
|
||||
local button = _G["PetActionButton" .. id]
|
||||
if button and button:GetButtonState() == "NORMAL" then
|
||||
button:SetButtonState("PUSHED")
|
||||
CastPetAction(id)
|
||||
end
|
||||
end
|
||||
|
||||
local function ST_PetActionButtonUp(id)
|
||||
local button = _G["PetActionButton" .. id]
|
||||
if button and button:GetButtonState() == "PUSHED" then
|
||||
button:SetButtonState("NORMAL")
|
||||
end
|
||||
end
|
||||
|
||||
-- Vanilla's BONUSACTIONBUTTON bindings are aliases for the pet-action
|
||||
-- handlers. Keep the same relationship while moving the cast to key-down.
|
||||
local function ST_BonusActionButtonDown(id)
|
||||
ST_PetActionButtonDown(id)
|
||||
end
|
||||
|
||||
local function ST_BonusActionButtonUp(id)
|
||||
ST_PetActionButtonUp(id)
|
||||
end
|
||||
|
||||
local function Install()
|
||||
_G.ActionButtonDown = ST_ActionButtonDown
|
||||
_G.ActionButtonUp = ST_ActionButtonUp
|
||||
_G.MultiActionButtonDown = ST_MultiActionButtonDown
|
||||
_G.MultiActionButtonUp = ST_MultiActionButtonUp
|
||||
_G.PetActionButtonDown = ST_PetActionButtonDown
|
||||
_G.PetActionButtonUp = ST_PetActionButtonUp
|
||||
|
||||
if type(_G.BonusActionButtonDown) == "function" then
|
||||
_G.BonusActionButtonDown = ST_BonusActionButtonDown
|
||||
end
|
||||
if type(_G.BonusActionButtonUp) == "function" then
|
||||
_G.BonusActionButtonUp = ST_BonusActionButtonUp
|
||||
end
|
||||
end
|
||||
|
||||
local function HandlersAreInstalled()
|
||||
return _G.ActionButtonDown == ST_ActionButtonDown
|
||||
and _G.ActionButtonUp == ST_ActionButtonUp
|
||||
and _G.MultiActionButtonDown == ST_MultiActionButtonDown
|
||||
and _G.MultiActionButtonUp == ST_MultiActionButtonUp
|
||||
and _G.PetActionButtonDown == ST_PetActionButtonDown
|
||||
and _G.PetActionButtonUp == ST_PetActionButtonUp
|
||||
end
|
||||
|
||||
-- Modified bindings (SHIFT-*, CTRL-*, ALT-*) are routed through ClassicAPI's
|
||||
-- normalized override-binding layer. Vanilla's runOnUp binding path is not
|
||||
-- reliable for every modified-key combination on custom 1.12 clients.
|
||||
-- Normal unmodified keys continue through the original ClassicSnowfall-style
|
||||
-- global handlers above.
|
||||
local bindingOwner = CreateFrame("Frame", "ShaguTweaksKeyDownBindingOwner", UIParent)
|
||||
local proxies = {}
|
||||
local specs = {}
|
||||
|
||||
local function AddSpec(command, kind, a, b)
|
||||
table.insert(specs, { command = command, kind = kind, a = a, b = b })
|
||||
end
|
||||
|
||||
for i = 1, 12 do
|
||||
AddSpec("ACTIONBUTTON" .. i, "action", i)
|
||||
AddSpec("MULTIACTIONBAR1BUTTON" .. i, "multi", "MultiBarBottomLeft", i)
|
||||
AddSpec("MULTIACTIONBAR2BUTTON" .. i, "multi", "MultiBarBottomRight", i)
|
||||
AddSpec("MULTIACTIONBAR3BUTTON" .. i, "multi", "MultiBarRight", i)
|
||||
AddSpec("MULTIACTIONBAR4BUTTON" .. i, "multi", "MultiBarLeft", i)
|
||||
AddSpec("BONUSACTIONBUTTON" .. i, "bonus", i)
|
||||
end
|
||||
|
||||
local function IsModifiedKey(key)
|
||||
if type(key) ~= "string" then return false end
|
||||
local upper = string.upper(key)
|
||||
return string.find(upper, "SHIFT-", 1, true)
|
||||
or string.find(upper, "CTRL-", 1, true)
|
||||
or string.find(upper, "ALT-", 1, true)
|
||||
end
|
||||
|
||||
local function GetProxy(spec, index)
|
||||
local name = "ShaguTweaksKeyDownProxy" .. index
|
||||
if proxies[index] then return proxies[index] end
|
||||
|
||||
local button = CreateFrame("Button", name, bindingOwner)
|
||||
button.spec = spec
|
||||
button:SetScript("OnClick", function()
|
||||
local s = this.spec
|
||||
if s.kind == "action" then
|
||||
ST_ActionButtonDown(s.a)
|
||||
ST_ActionButtonUp(s.a)
|
||||
elseif s.kind == "multi" then
|
||||
ST_MultiActionButtonDown(s.a, s.b)
|
||||
ST_MultiActionButtonUp(s.a, s.b)
|
||||
elseif s.kind == "bonus" then
|
||||
ST_BonusActionButtonDown(s.a)
|
||||
ST_BonusActionButtonUp(s.a)
|
||||
end
|
||||
end)
|
||||
proxies[index] = button
|
||||
return button
|
||||
end
|
||||
|
||||
local refreshingBindings
|
||||
local function RefreshModifiedBindings()
|
||||
if refreshingBindings then return end
|
||||
if not API or not API.overridebindings then return end
|
||||
|
||||
refreshingBindings = true
|
||||
API.ClearOverrideBindings(bindingOwner)
|
||||
|
||||
for index, spec in ipairs(specs) do
|
||||
local key1, key2 = GetBindingKey(spec.command)
|
||||
local proxy = GetProxy(spec, index)
|
||||
|
||||
if IsModifiedKey(key1) then
|
||||
API.SetOverrideBindingClick(bindingOwner, true, key1, proxy:GetName())
|
||||
end
|
||||
if IsModifiedKey(key2) then
|
||||
API.SetOverrideBindingClick(bindingOwner, true, key2, proxy:GetName())
|
||||
end
|
||||
end
|
||||
|
||||
refreshingBindings = nil
|
||||
end
|
||||
|
||||
Install()
|
||||
RefreshModifiedBindings()
|
||||
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:RegisterEvent("PLAYER_LOGIN")
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
frame:RegisterEvent("UPDATE_BINDINGS")
|
||||
frame.elapsed = 0
|
||||
frame.guardUntil = 0
|
||||
|
||||
local function GuardOnUpdate()
|
||||
if not frame.guardUntil or frame.guardUntil <= GetTime() then
|
||||
frame:SetScript("OnUpdate", nil)
|
||||
return
|
||||
end
|
||||
|
||||
frame.elapsed = frame.elapsed + (arg1 or 0)
|
||||
if frame.elapsed < 0.25 then return end
|
||||
frame.elapsed = 0
|
||||
|
||||
if not HandlersAreInstalled() then Install() end
|
||||
end
|
||||
|
||||
frame:SetScript("OnEvent", function()
|
||||
Install()
|
||||
RefreshModifiedBindings()
|
||||
|
||||
if event == "PLAYER_LOGIN" or event == "PLAYER_ENTERING_WORLD" then
|
||||
frame.guardUntil = GetTime() + 8
|
||||
frame.elapsed = 0
|
||||
frame:SetScript("OnUpdate", GuardOnUpdate)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,70 @@
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
local T = ShaguTweaks.T
|
||||
local HookScript = ShaguTweaks.HookScript
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Metric Range"],
|
||||
description = T["Displays tooltip range units in metres instead of yards."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Tooltip & Items"],
|
||||
enabled = true,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
-- Avoid double processing while the old standalone addon is still enabled.
|
||||
if IsAddOnLoaded("MetricRange") then return end
|
||||
|
||||
local function ConvertText(text)
|
||||
if type(text) ~= "string" then return text end
|
||||
|
||||
-- Intentionally keep the original behavior: only replace the displayed
|
||||
-- unit label. Do not numerically convert the range value.
|
||||
text = string.gsub(text, " yards", " metres")
|
||||
text = string.gsub(text, " yard", " metre")
|
||||
text = string.gsub(text, " yd", " m")
|
||||
return text
|
||||
end
|
||||
|
||||
local function ConvertTooltip(tooltip)
|
||||
if not tooltip or not tooltip.GetName then return end
|
||||
|
||||
local name = tooltip:GetName()
|
||||
if not name then return end
|
||||
|
||||
for i = 1, 30 do
|
||||
local left = _G[name .. "TextLeft" .. i]
|
||||
if left then
|
||||
local old = left:GetText()
|
||||
if old then
|
||||
local new = ConvertText(old)
|
||||
if new ~= old then left:SetText(new) end
|
||||
end
|
||||
end
|
||||
|
||||
local right = _G[name .. "TextRight" .. i]
|
||||
if right then
|
||||
local old = right:GetText()
|
||||
if old then
|
||||
local new = ConvertText(old)
|
||||
if new ~= old then right:SetText(new) end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function HookTooltip(tooltip)
|
||||
if not tooltip then return end
|
||||
HookScript(tooltip, "OnShow", function()
|
||||
ConvertTooltip(tooltip)
|
||||
end)
|
||||
end
|
||||
|
||||
HookTooltip(GameTooltip)
|
||||
HookTooltip(ItemRefTooltip)
|
||||
HookTooltip(ShoppingTooltip1)
|
||||
HookTooltip(ShoppingTooltip2)
|
||||
HookTooltip(ShoppingTooltip3)
|
||||
|
||||
if GameTooltip and GameTooltip:IsVisible() then ConvertTooltip(GameTooltip) end
|
||||
if ItemRefTooltip and ItemRefTooltip:IsVisible() then ConvertTooltip(ItemRefTooltip) end
|
||||
end
|
||||
@@ -7,6 +7,7 @@ local module = ShaguTweaks:register({
|
||||
title = T["Reveal World Map"],
|
||||
description = T["Reveals unexplored world map areas and shows exploration hints."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = false },
|
||||
category = T["World Map"],
|
||||
maintainer = "@shagu (GitHub)",
|
||||
enabled = true,
|
||||
config = {
|
||||
|
||||
Reference in New Issue
Block a user