Add optimized TokensWorth chat and loot modules

Add Block NPC Spam, World Chat Hider, and Loot Quality to Extras with shared chat filtering, event-driven loot quality handling, runtime safety fixes, and updated documentation/provenance.
This commit is contained in:
2026-09-07 09:52:54 +02:00
committed by GitHub
parent a34ad33bfa
commit 3c4083b3db
7 changed files with 366 additions and 1 deletions
+10 -1
View File
@@ -43,8 +43,11 @@ Settings: **Esc → Advanced Options**.
- Buy Em All uses ClassicAPI merchant, item count and bag-family data, including specialty bags.
- Added modifier-aware Key-Down Casting with Shift/Ctrl/Alt binding support and an independent Alt Self-Cast option.
- Added Metric Range for metre labels in range tooltips without changing numeric values.
- Added optimized modules adapted from TokensWorth/ShaguTweaks-mods: Mouseover Right bars, Hide Macro Text, Unit Frame Abbreviated Names, Cursor Tooltip, Hide Combat Tooltip and MiniMap Framerate & Latency.
- Added optimized modules adapted from TokensWorth/ShaguTweaks-mods: Mouseover Right bars, Hide Macro Text, Unit Frame Abbreviated Names, Cursor Tooltip, Hide Combat Tooltip, MiniMap Framerate & Latency, Block NPC Spam, World Chat Hider and Loot Quality.
- MiniMap Framerate & Latency updates both counters through one ClassicAPI ticker instead of permanent per-frame handlers.
- Block NPC Spam and World Chat Hider share one on-demand chat filter dispatcher instead of stacking separate global chat wrappers.
- World Chat Hider suppresses World messages locally in instances and never leaves or rejoins the channel.
- Loot Quality is event-driven and checks all current loot slots instead of only visible loot buttons.
- Hide Combat Tooltip uses ClassicAPI modifier-state events instead of permanent per-frame modifier polling.
- Various stability fixes across legacy ShaguTweaks Extras modules.
@@ -96,6 +99,10 @@ Other modules can also benefit indirectly from ClassicAPI through shared ShaguTw
- Auction Alt-Buy
- Buy Em All
### Loot
- Loot Quality
### Tooltip & Items
- Metric Range
@@ -113,6 +120,8 @@ Other modules can also benefit indirectly from ClassicAPI through shared ShaguTw
### Chat
- Block NPC Spam
- World Chat Hider
- Chat Timestamps
- Center Text Input Box
- Enable Text Shadow
+6
View File
@@ -39,6 +39,9 @@ mods\bag-search.lua
mods\auction-alt-buy.lua
mods\buy-em-all.lua
# loot
mods\loot-quality.lua
# tooltip & items
mods\metric-range.lua
mods\cursor-tooltip.lua
@@ -56,6 +59,9 @@ mods\macro-icons.lua
mods\macro-tweaks.lua
# chat
mods\chat-filter-common.lua
mods\chat-npc-spam.lua
mods\world-chat-hider.lua
mods\chat-input-center.lua
mods\chat-text-shadow.lua
mods\chat-timestamps.lua
+3
View File
@@ -38,6 +38,9 @@ The following modules in this fork contain code adapted from
- `mods/cursor-tooltip.lua`
- `mods/hide-combat-tooltip.lua`
- `mods/minimap-framerate-latency.lua`
- `mods/chat-npc-spam.lua`
- `mods/world-chat-hider.lua`
- `mods/loot-quality.lua`
Source:
- https://github.com/TokensWorth/ShaguTweaks-mods
+68
View File
@@ -0,0 +1,68 @@
-- Shared chat-filter dispatcher for Extras modules.
-- Installs one ChatFrame_OnEvent wrapper only when a filter is enabled.
local Filter = ShaguTweaks.ExtrasChatFilter
if not Filter then
Filter = {
handlers = {},
order = {},
known = {},
installed = false,
installer = nil,
}
ShaguTweaks.ExtrasChatFilter = Filter
end
function Filter:Install()
if self.installed then return end
self.installed = true
self.original = ChatFrame_OnEvent
ChatFrame_OnEvent = function(event)
for i = 1, table.getn(Filter.order) do
local current = Filter.handlers[Filter.order[i]]
if current and current(event) then
return
end
end
if Filter.original then
return Filter.original(event)
end
end
end
function Filter:ScheduleInstall()
if self.installed or self.installer then return end
-- ShaguTweaks enables modules during VARIABLES_LOADED in unspecified table
-- order. Install on PLAYER_ENTERING_WORLD so this dispatcher becomes the
-- outer wrapper after the core Chat Spam Filter regardless of module order.
-- That prevents locally hidden World/NPC messages from entering its cache.
self.installer = CreateFrame("Frame")
self.installer:RegisterEvent("PLAYER_ENTERING_WORLD")
self.installer:SetScript("OnEvent", function()
Filter:Install()
this:UnregisterAllEvents()
this:Hide()
Filter.installer = nil
end)
end
function Filter:Register(key, handler)
if type(key) ~= "string" or type(handler) ~= "function" then return end
if not self.known[key] then
self.known[key] = true
self.order[table.getn(self.order) + 1] = key
end
self.handlers[key] = handler
self:ScheduleInstall()
end
function Filter:Unregister(key)
self.handlers[key] = nil
end
+92
View File
@@ -0,0 +1,92 @@
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
local T = ShaguTweaks.T
local Filter = ShaguTweaks.ExtrasChatFilter
local module = ShaguTweaks:register({
title = T["Block NPC Spam"],
description = T["Blocks known repetitive NPC say/yell spam messages."],
expansions = { ["vanilla"] = true, ["tbc"] = nil },
category = T["Chat"],
enabled = nil,
})
local blockedEvents = {
["CHAT_MSG_MONSTER_SAY"] = true,
["CHAT_MSG_MONSTER_YELL"] = true,
}
local blockedNPCs = {}
local npcNames = {
-- enUS
"Tansy Sparkpen",
"Fara Boltbreaker",
"Shellcoin Promoter",
-- ruRU
"Зазывала ярмарки Новолуния",
"Томас Миллер",
"Уильям",
"Донна",
"Жюстина Демалье",
"Мерлис Малаган",
"Лиана Пирс",
"Сюзанна",
"Джейни Аншип",
}
for _, name in pairs(npcNames) do
blockedNPCs[name] = true
blockedNPCs[string.lower(name)] = true
end
local blockedPhrases = {
{ "shellcoin", "invest" },
{ "shells", "trade" },
{ "shells", "money" },
}
local function IsBlockedNPC(sender)
if not sender then return false end
return blockedNPCs[sender] or blockedNPCs[string.lower(sender)] or false
end
local function IsBlockedPhrase(message)
if not message then return false end
local normalized = string.lower(string.gsub(message, "[^A-Za-z0-9]", ""))
for _, phrase in pairs(blockedPhrases) do
local matched = true
for _, word in pairs(phrase) do
if not string.find(normalized, word, 1, true) then
matched = false
break
end
end
if matched then return true end
end
return false
end
local function FilterNPCSpam(event)
if not blockedEvents[event] then return false end
if not arg1 or not arg2 then return false end
return IsBlockedNPC(arg2) or IsBlockedPhrase(arg1)
end
module.enable = function(self)
if Filter then
Filter:Register("BlockNPCSpam", FilterNPCSpam)
end
end
module.disable = function(self)
if Filter then
Filter:Unregister("BlockNPCSpam")
end
end
+128
View File
@@ -0,0 +1,128 @@
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
local T = ShaguTweaks.T
local module = ShaguTweaks:register({
title = T["Loot Quality"],
description = T["Colors the loot frame using the highest item quality in the current loot window."],
expansions = { ["vanilla"] = true, ["tbc"] = nil },
category = T["Loot"],
enabled = nil,
})
local MIN_QUALITY = 2 -- uncommon / green
local function FindLootTitle()
local regions = { LootFrame:GetRegions() }
for i = 1, table.getn(regions) do
local region = regions[i]
-- Some Vanilla/Turtle regions expose GetText without being FontStrings.
-- Only keep a region that can actually be recolored.
if region
and type(region.GetText) == "function"
and type(region.SetTextColor) == "function"
and region:GetText() == ITEMS then
return region
end
end
end
module.enable = function(self)
if not self.border then
self.border = LootFrame:CreateTexture(nil, "OVERLAY")
self.border:SetTexture("Interface\\LootFrame\\UI-LootPanel")
self.border:SetPoint("TOPLEFT", LootFrame, "TOPLEFT", -4, 3)
self.border:SetPoint("BOTTOMRIGHT", LootFrame, "BOTTOMRIGHT", 5, -3)
self.border:SetDrawLayer("ARTWORK")
self.highlight = LootFrame:CreateTexture(nil, "OVERLAY")
self.highlight:SetTexture("Interface\\LootFrame\\UI-LootPanel")
self.highlight:SetAllPoints(self.border)
self.highlight:SetDrawLayer("ARTWORK")
self.highlight:SetBlendMode("ADD")
end
self.title = self.title or FindLootTitle()
if self.title
and not self.titleColor
and type(self.title.GetTextColor) == "function" then
local r, g, b, a = self.title:GetTextColor()
self.titleColor = { r or 1, g or .82, b or 0, a or 1 }
end
local function RestoreTitle()
if not self.title or type(self.title.SetTextColor) ~= "function" then return end
local color = self.titleColor
if color then
self.title:SetTextColor(color[1], color[2], color[3], color[4])
else
self.title:SetTextColor(1, .82, 0)
end
end
local function ResetVisuals()
self.border:Hide()
self.highlight:Hide()
RestoreTitle()
end
local function UpdateQuality()
local highestQuality = 0
local count = GetNumLootItems() or 0
for i = 1, count do
if LootSlotIsItem(i) then
local _, _, _, quality = GetLootSlotInfo(i)
quality = tonumber(quality) or 0
if quality > highestQuality then
highestQuality = quality
end
end
end
local color = ITEM_QUALITY_COLORS and ITEM_QUALITY_COLORS[highestQuality]
if highestQuality < MIN_QUALITY or not color then
ResetVisuals()
return
end
self.border:SetVertexColor(color.r, color.g, color.b)
self.highlight:SetVertexColor(color.r, color.g, color.b)
self.border:Show()
self.highlight:Show()
if self.title and type(self.title.SetTextColor) == "function" then
self.title:SetTextColor(color.r, color.g, color.b)
end
end
self.ResetVisuals = ResetVisuals
self.events = self.events or CreateFrame("Frame")
self.events:UnregisterAllEvents()
self.events:RegisterEvent("LOOT_OPENED")
self.events:RegisterEvent("LOOT_SLOT_CLEARED")
self.events:RegisterEvent("LOOT_CLOSED")
self.events:SetScript("OnEvent", function()
if event == "LOOT_CLOSED" then
ResetVisuals()
else
UpdateQuality()
end
end)
ResetVisuals()
end
module.disable = function(self)
if self.events then
self.events:UnregisterAllEvents()
end
if self.ResetVisuals then
self.ResetVisuals()
end
end
+59
View File
@@ -0,0 +1,59 @@
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
local T = ShaguTweaks.T
local Filter = ShaguTweaks.ExtrasChatFilter
local module = ShaguTweaks:register({
title = T["World Chat Hider"],
description = T["Hides World channel messages while inside an instance without leaving the channel."],
expansions = { ["vanilla"] = true, ["tbc"] = nil },
category = T["Chat"],
enabled = nil,
})
local function IsInsideInstance()
if type(IsInInstance) ~= "function" then return false end
local inside = IsInInstance()
return inside == 1 or inside == true
end
local function IsWorldChannel()
-- Vanilla 1.12 CHAT_MSG_CHANNEL exposes the base channel name in arg9.
-- Custom channel names are not localized, so comparing the actual event is
-- both cheaper and safer than querying GetChannelName("world") every time.
if arg9 and string.lower(arg9) == "world" then
return true
end
-- Conservative fallback for clients that omit arg9: arg4 is the numbered
-- channel label (for example "5. World").
if arg4 then
local full = string.lower(arg4)
if full == "world" then return true end
local _, _, base = string.find(full, "^%d+%.%s*(.+)$")
if base == "world" then return true end
end
return false
end
local function FilterWorldChat(event)
if event ~= "CHAT_MSG_CHANNEL" then return false end
if not IsInsideInstance() then return false end
return IsWorldChannel()
end
module.enable = function(self)
if Filter then
Filter:Register("WorldChatHider", FilterWorldChat)
end
end
module.disable = function(self)
if Filter then
Filter:Unregister("WorldChatHider")
end
end