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.
|
- 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.
|
- 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.
|
- 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.
|
- Various stability fixes across legacy ShaguTweaks Extras modules.
|
||||||
|
|
||||||
## 🔷 Mods using ClassicAPI integration
|
## 🔷 Mods using ClassicAPI integration
|
||||||
|
|
||||||
|
- Auction Alt-Buy
|
||||||
- Bag Item Click
|
- Bag Item Click
|
||||||
- Bag Search Bar
|
- Bag Search Bar
|
||||||
|
- Buy Em All
|
||||||
|
- Key-Down Casting
|
||||||
|
- Alt Self-Cast
|
||||||
- Macro Icons
|
- Macro Icons
|
||||||
- Macro Tweaks
|
- Macro Tweaks
|
||||||
- Raid Frames
|
- Raid Frames
|
||||||
@@ -66,6 +73,26 @@ Other modules can also benefit indirectly from ClassicAPI through shared ShaguTw
|
|||||||
- Reagent Counter
|
- Reagent Counter
|
||||||
- Show Bags
|
- Show Bags
|
||||||
- Show Micro Menu
|
- 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
|
### Chat
|
||||||
|
|
||||||
@@ -73,12 +100,6 @@ Other modules can also benefit indirectly from ClassicAPI through shared ShaguTw
|
|||||||
- Center Text Input Box
|
- Center Text Input Box
|
||||||
- Enable Text Shadow
|
- Enable Text Shadow
|
||||||
|
|
||||||
### Bags & World Map
|
|
||||||
|
|
||||||
- Bag Item Click
|
|
||||||
- Bag Search Bar
|
|
||||||
- Reveal World Map
|
|
||||||
|
|
||||||
### Macro
|
### Macro
|
||||||
|
|
||||||
- Macro Icons
|
- Macro Icons
|
||||||
|
|||||||
+19
-7
@@ -18,17 +18,33 @@ locales\translations_zhTW.lua
|
|||||||
# core
|
# core
|
||||||
main.lua
|
main.lua
|
||||||
|
|
||||||
# general
|
# action bar
|
||||||
mods\macro-icons.lua
|
|
||||||
mods\macro-tweaks.lua
|
|
||||||
mods\actionbar-df-gryphon.lua
|
mods\actionbar-df-gryphon.lua
|
||||||
mods\actionbar-right-center.lua
|
mods\actionbar-right-center.lua
|
||||||
mods\actionbar-reagents.lua
|
mods\actionbar-reagents.lua
|
||||||
mods\actionbar-float.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-item-click.lua
|
||||||
mods\bag-search.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
|
mods\worldmap-reveal.lua
|
||||||
|
|
||||||
|
# macro
|
||||||
|
mods\macro-icons.lua
|
||||||
|
mods\macro-tweaks.lua
|
||||||
|
|
||||||
# chat
|
# chat
|
||||||
mods\chat-input-center.lua
|
mods\chat-input-center.lua
|
||||||
mods\chat-text-shadow.lua
|
mods\chat-text-shadow.lua
|
||||||
@@ -44,7 +60,3 @@ mods\raid-aggro-indicator.lua
|
|||||||
mods\raid-healing-predictions.lua
|
mods\raid-healing-predictions.lua
|
||||||
mods\raid-compact-layout.lua
|
mods\raid-compact-layout.lua
|
||||||
mods\raid-hide-party.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"],
|
title = T["Bag Item Click"],
|
||||||
description = T["Send items to trade window or auction house search via right click."],
|
description = T["Send items to trade window or auction house search via right click."],
|
||||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Bags & Inventory"],
|
||||||
maintainer = "@shagu (GitHub)",
|
maintainer = "@shagu (GitHub)",
|
||||||
enabled = true,
|
enabled = true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ local module = ShaguTweaks:register({
|
|||||||
title = T["Bag Search Bar"],
|
title = T["Bag Search Bar"],
|
||||||
description = T["Adds a search field to the bag which allows you to search bag, keyring and bank slots."],
|
description = T["Adds a search field to the bag which allows you to search bag, keyring and bank slots."],
|
||||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Bags & Inventory"],
|
||||||
maintainer = "@shagu (GitHub)",
|
maintainer = "@shagu (GitHub)",
|
||||||
enabled = true,
|
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"],
|
title = T["Reveal World Map"],
|
||||||
description = T["Reveals unexplored world map areas and shows exploration hints."],
|
description = T["Reveals unexplored world map areas and shows exploration hints."],
|
||||||
expansions = { ["vanilla"] = true, ["tbc"] = false },
|
expansions = { ["vanilla"] = true, ["tbc"] = false },
|
||||||
|
category = T["World Map"],
|
||||||
maintainer = "@shagu (GitHub)",
|
maintainer = "@shagu (GitHub)",
|
||||||
enabled = true,
|
enabled = true,
|
||||||
config = {
|
config = {
|
||||||
|
|||||||
Reference in New Issue
Block a user