Files
wow-Heimdall/Modules/MinimapTagger.lua

598 lines
20 KiB
Lua

local _, shared = ...
---@cast shared HeimdallShared
local ModuleName = "MinimapTagger"
---@class HeimdallMinimapTaggerConfig
---@field enabled boolean
---@field debug boolean
---@field channels string[]
---@field throttle number
---@field scale number
---@field tagTTL number
---@field tagSound boolean
---@field tagSoundFile string
---@field tagSoundThrottle number
---@field tagTextureFile string
---@field alertTTL number
---@field alertSound boolean
---@field alertSoundFile string
---@field alertSoundThrottle number
---@field alertTextureFile string
---@field combatTTL number
---@field combatSound boolean
---@field combatSoundFile string
---@field combatSoundThrottle number
---@field combatTextureFile string
---@field helpTTL number
---@field helpSound boolean
---@field helpSoundFile string
---@field helpSoundThrottle number
---@field helpTextureFile string
local HeimdallRoot = "Interface\\AddOns\\Heimdall\\"
local SoundRoot = HeimdallRoot .. "Sounds\\"
local TextureRoot = HeimdallRoot .. "Texture\\"
--/run local a=GetChannelName("Agent")local b,c=GetPlayerMapPosition("player")b,c=b*100,c*100;local d=string.format("I need help at %s (%s) [%s](%2.2f, %2.2f)",GetZoneText(),GetSubZoneText(),GetCurrentMapAreaID(),b,c)SendChatMessage(d,"CHANNEL",nil,a)
---@class MinimapTagger
shared.MinimapTagger = {
Init = function()
---@param x number
---@param y number
---@param frame Frame
---@param scale number?
---@param ttl number?
local function PlantFrame(x, y, frame, scale, ttl)
if not BattlefieldMinimap then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] BattlefieldMinimap not found", ModuleName))
end
return
end
scale = scale or 1
ttl = ttl or 1
local w, h = BattlefieldMinimap:GetSize()
w, h = w * BattlefieldMinimap:GetEffectiveScale(), h * BattlefieldMinimap:GetEffectiveScale()
local maxSize = w > h and w or h
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Minimap size: %d", ModuleName, maxSize))
print(string.format("[%s] Scale: %d", ModuleName, scale))
print(string.format("[%s] TTL: %d", ModuleName, ttl))
end
local iconSize = maxSize * 0.05
iconSize = iconSize * scale
x, y = x / 100, y / 100
-- Could do with how... I have no idea, but this seems more accurate than without
--x, y = x - 0.01, y - 0.01
local offsetx, offsety = w * x, h * y
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Alert position: %d, %d", ModuleName, x, y))
print(string.format("[%s] Alert offset: %d, %d", ModuleName, offsetx, offsety))
end
frame:Hide()
frame:SetSize(iconSize, iconSize)
frame:SetFrameStrata("HIGH")
frame:SetFrameLevel(100)
frame:SetPoint("CENTER", BattlefieldMinimap, "TOPLEFT", offsetx, -offsety)
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Alert frame created, OnUpdate hooked", ModuleName))
end
frame:SetScript("OnShow", function(self)
self:SetAlpha(1)
self.custom.busy = true
self.custom.progress = 0
self:SetScript("OnUpdate", function(selff, elapsed)
self.custom.progress = self.custom.progress + elapsed
local progress = self.custom.progress / ttl
-- if Heimdall_Data.config.minimapTagger.debug then
-- print(string.format("[%s] Alert progress%%: %f", ModuleName, progress))
-- print(string.format("[%s] Alert progress: %f", ModuleName, self.custom.progress))
-- print(string.format("[%s] Alert ttl: %d", ModuleName, Heimdall_Data.config.minimapTagger.ttl))
-- end
self:SetAlpha(1 - progress)
if progress >= 1 then
self:Hide()
self.custom.busy = false
self:SetScript("OnUpdate", nil)
end
end)
end)
frame:Show()
end
--region Alert
---@type Frame[]
local alertFramePool = {}
local alertFramePoolMaxSize = 20
for i = 1, alertFramePoolMaxSize do
local frame = CreateFrame("Frame")
frame.custom = { busy = false }
local texture = frame:CreateTexture(nil, "ARTWORK")
texture:SetAllPoints(frame)
texture:SetTexture(TextureRoot .. Heimdall_Data.config.minimapTagger.alertTextureFile)
table.insert(alertFramePool, frame)
end
local muteAlertUntil = 0
---@param x number|nil
---@param y number|nil
---@param scale number?
---@param doTag boolean?
local function PlantAlert(x, y, scale, doTag)
if x == nil or y == nil then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Alert position is nil, ignoring", ModuleName))
end
return
end
if doTag == nil then doTag = true end
local frame = nil
for _, alertFrame in ipairs(alertFramePool) do
---@diagnostic disable-next-line: undefined-field
if not alertFrame.custom.busy then
frame = alertFrame
break
end
end
if not frame then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Alert frame pool is full and could not get frame", ModuleName))
end
return
end
if Heimdall_Data.config.minimapTagger.alertSound then
if Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Playing alert sound: %s",
ModuleName,
Heimdall_Data.config.minimapTagger.alertSoundFile
)
)
end
if muteAlertUntil > GetTime() then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Alert sound is muted until %d", ModuleName, muteAlertUntil))
end
else
muteAlertUntil = GetTime() + Heimdall_Data.config.minimapTagger.alertSoundThrottle
local ok = PlaySoundFile(SoundRoot .. Heimdall_Data.config.minimapTagger.alertSoundFile, "Master")
if not ok and Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Failed to play alert sound: %s",
ModuleName,
Heimdall_Data.config.minimapTagger.alertSoundFile
)
)
end
end
end
if doTag then PlantFrame(x, y, frame, scale, Heimdall_Data.config.minimapTagger.alertTTL) end
end
--endregion
--region Tag
---@type Frame[]
local tagFramePool = {}
local tagFramePoolMaxSize = 20
for i = 1, tagFramePoolMaxSize do
local frame = CreateFrame("Frame")
frame.custom = { busy = false }
local texture = frame:CreateTexture(nil, "ARTWORK")
texture:SetAllPoints(frame)
texture:SetTexture(TextureRoot .. Heimdall_Data.config.minimapTagger.tagTextureFile)
table.insert(tagFramePool, frame)
end
local muteTagUntil = 0
---@param x number|nil
---@param y number|nil
---@param scale number?
---@param doTag boolean?
local function PlantTag(x, y, scale, doTag)
if x == nil or y == nil then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Tag position is nil, ignoring", ModuleName))
end
return
end
if doTag == nil then doTag = true end
local frame = nil
for _, tagFrame in ipairs(tagFramePool) do
---@diagnostic disable-next-line: undefined-field
if not tagFrame.custom.busy then
frame = tagFrame
break
end
end
if not frame then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Tag frame pool is full and could not get frame", ModuleName))
end
return
end
if Heimdall_Data.config.minimapTagger.tagSound then
if Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Playing tag sound: %s",
ModuleName,
Heimdall_Data.config.minimapTagger.tagSoundFile
)
)
end
if muteTagUntil > GetTime() then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Tag sound is muted until %d", ModuleName, muteTagUntil))
end
else
muteTagUntil = GetTime() + Heimdall_Data.config.minimapTagger.tagSoundThrottle
local ok = PlaySoundFile(SoundRoot .. Heimdall_Data.config.minimapTagger.tagSoundFile, "Master")
if not ok and Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Failed to play tag sound: %s",
ModuleName,
Heimdall_Data.config.minimapTagger.tagSoundFile
)
)
end
end
end
if doTag then PlantFrame(x, y, frame, scale, Heimdall_Data.config.minimapTagger.tagTTL) end
end
--endregion
--region Combat
---@type Frame[]
local combatFramePool = {}
local combatFramePoolMaxSize = 20
for i = 1, combatFramePoolMaxSize do
local frame = CreateFrame("Frame")
frame.custom = { busy = false }
local texture = frame:CreateTexture(nil, "ARTWORK")
texture:SetAllPoints(frame)
texture:SetTexture(TextureRoot .. Heimdall_Data.config.minimapTagger.combatTextureFile)
table.insert(combatFramePool, frame)
end
local muteCombatUntil = 0
---@param x number|nil
---@param y number|nil
---@param scale number?
---@param doTag boolean?
local function PlantCombat(x, y, scale, doTag)
if x == nil or y == nil then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Combat position is nil, ignoring", ModuleName))
end
return
end
if doTag == nil then doTag = true end
local frame = nil
for _, combatFrame in ipairs(combatFramePool) do
---@diagnostic disable-next-line: undefined-field
if not combatFrame.custom.busy then
frame = combatFrame
break
end
end
if not frame then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Battle frame pool is full and could not get frame", ModuleName))
end
return
end
if Heimdall_Data.config.minimapTagger.combatSound then
if Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Playing combat sound: %s",
ModuleName,
Heimdall_Data.config.minimapTagger.combatSoundFile
)
)
end
if muteCombatUntil > GetTime() then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Combat sound is muted until %d", ModuleName, muteCombatUntil))
end
else
muteCombatUntil = GetTime() + Heimdall_Data.config.minimapTagger.combatSoundThrottle
local ok = PlaySoundFile(SoundRoot .. Heimdall_Data.config.minimapTagger.combatSoundFile, "Master")
if not ok and Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Failed to play combat sound: %s",
ModuleName,
Heimdall_Data.config.minimapTagger.combatSoundFile
)
)
end
end
end
if doTag then PlantFrame(x, y, frame, scale, Heimdall_Data.config.minimapTagger.combatTTL) end
end
--endregion
--region Help
---@type Frame[]
local helpFramePool = {}
local helpFramePoolMaxSize = 20
for i = 1, helpFramePoolMaxSize do
local frame = CreateFrame("Frame")
frame.custom = { busy = false }
local texture = frame:CreateTexture(nil, "ARTWORK")
texture:SetAllPoints(frame)
texture:SetTexture(TextureRoot .. Heimdall_Data.config.minimapTagger.helpTextureFile)
table.insert(helpFramePool, frame)
end
local muteHelpUntil = 0
---@param x number|nil
---@param y number|nil
---@param scale number?
---@param doTag boolean?
local function PlantHelp(x, y, scale, doTag)
if x == nil or y == nil then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Help position is nil, ignoring", ModuleName))
end
return
end
if doTag == nil then doTag = true end
local frame = nil
for _, helpFrame in ipairs(helpFramePool) do
---@diagnostic disable-next-line: undefined-field
if not helpFrame.custom.busy then
frame = helpFrame
break
end
end
if not frame then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Help frame pool is full and could not get frame", ModuleName))
end
return
end
if Heimdall_Data.config.minimapTagger.helpSound then
if Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Playing help sound: %s",
ModuleName,
Heimdall_Data.config.minimapTagger.helpSoundFile
)
)
end
if muteHelpUntil > GetTime() then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Help sound is muted until %d", ModuleName, muteHelpUntil))
end
else
muteHelpUntil = GetTime() + Heimdall_Data.config.minimapTagger.helpSoundThrottle
local ok = PlaySoundFile(SoundRoot .. Heimdall_Data.config.minimapTagger.helpSoundFile, "Master")
if not ok and Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Failed to play help sound: %s",
ModuleName,
Heimdall_Data.config.minimapTagger.helpSoundFile
)
)
end
end
end
if doTag then PlantFrame(x, y, frame, scale, Heimdall_Data.config.minimapTagger.helpTTL) end
end
--endregion
local pauseUntil = 0
local frame = CreateFrame("Frame")
frame:RegisterEvent("WORLD_MAP_UPDATE")
frame:SetScript("OnEvent", function(self, event, addon)
if pauseUntil > GetTime() then return end
pauseUntil = GetTime() + 1
if not BattlefieldMinimap then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] BattlefieldMinimap not found", ModuleName))
end
return
end
if not Heimdall_Data.config.minimapTagger.enabled then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] MinimapTagger is disabled", ModuleName))
end
return
end
local scale = Heimdall_Data.config.minimapTagger.scale
BattlefieldMinimap:SetScale(scale)
BattlefieldMinimap:SetMovable(true)
BattlefieldMinimap:EnableMouse(true)
BattlefieldMinimap:RegisterForDrag("LeftButton")
BattlefieldMinimap:SetScript("OnDragStart", function(selff) selff:StartMoving() end)
BattlefieldMinimap:SetScript("OnDragStop", function(selff) selff:StopMovingOrSizing() end)
BattlefieldMinimapBackground:Hide()
BattlefieldMinimapCloseButton:Hide()
BattlefieldMinimapCorner:Hide()
BattlefieldMinimap:HookScript("OnHide", function(selff)
for _, alertFrame in ipairs(alertFramePool) do
alertFrame:Hide()
---@diagnostic disable-next-line: undefined-field
alertFrame.custom.busy = false
end
for _, tagFrame in ipairs(tagFramePool) do
tagFrame:Hide()
---@diagnostic disable-next-line: undefined-field
tagFrame.custom.busy = false
end
-- What the fuck is this global?
for _, battleFrame in ipairs(battleFramePool) do
battleFrame:Hide()
battleFrame.custom.busy = false
end
end)
end)
local chatFrame = CreateFrame("Frame")
chatFrame:RegisterEvent("CHAT_MSG_CHANNEL")
chatFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
--if Heimdall_Data.config.echoer.debug then
-- print(string.format("[%s] Channel message received from: %s", ModuleName, sender))
--end
if not Heimdall_Data.config.minimapTagger.enabled then
--if Heimdall_Data.config.echoer.debug then
-- print(string.format("[%s] Module disabled, ignoring message", ModuleName))
--end
return
end
local channelId = select(6, ...)
local _, channelname = GetChannelName(channelId)
local ok = false
for _, channel in pairs(Heimdall_Data.config.minimapTagger.channels) do
if channelname == channel then
ok = true
break
end
end
if not ok then
if Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Ignoring message from non-master channel: %s, need %s",
ModuleName,
channelname,
Heimdall_Data.config.minimapTagger.masterChannel
)
)
end
return
end
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
shared.dump(Heimdall_Data.config.minimapTagger)
end
local doTag = true
local messageMapId = string.match(msg, "%[(%d+)%]") or 0
if messageMapId then messageMapId = tonumber(messageMapId) end
local currentMapId = GetCurrentMapAreaID()
if currentMapId ~= messageMapId then
if Heimdall_Data.config.minimapTagger.debug then
print(
string.format(
"[%s] Current map ID (%d) does not match message map ID (%d), ignoring message",
ModuleName,
currentMapId,
messageMapId
)
)
end
doTag = false
end
--region Tag
if string.find(msg, "^I see") then
if Heimdall_Data.config.minimapTagger.tagTTL == 0 then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Tag TTL is 0, ignoring message: %s", ModuleName, msg))
end
return
end
local x, y = string.match(msg, "%((%d+%.%d+)%s*,%s*(%d+%.%d+)%)")
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Found alert position: %s, %s", ModuleName, tostring(x), tostring(y)))
end
if x and y then PlantTag(tonumber(x), tonumber(y), 2, doTag) end
end
--endregion
--region Combat
if string.find(msg, "^I am in combat with") then
if Heimdall_Data.config.minimapTagger.combatTTL == 0 then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Combat TTL is 0, ignoring message: %s", ModuleName, msg))
end
return
end
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Found combat alert in message: %s", ModuleName, msg))
end
local x, y = string.match(msg, "%((%d+%.%d+)%s*,%s*(%d+%.%d+)%)")
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Found combat position: %s, %s", ModuleName, tostring(x), tostring(y)))
end
if x and y then PlantCombat(tonumber(x), tonumber(y), 2, doTag) end
end
--endregion
--region Death
if string.find(msg, " killed ") then
if Heimdall_Data.config.minimapTagger.alertTTL == 0 then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Alert TTL is 0, ignoring message: %s", ModuleName, msg))
end
return
end
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Found death alert in message: %s", ModuleName, msg))
end
local x, y = string.match(msg, "%((%d+%.%d+)%s*,%s*(%d+%.%d+)%)")
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Found death position: %s, %s", ModuleName, tostring(x), tostring(y)))
end
if x and y then PlantAlert(tonumber(x), tonumber(y), 2, doTag) end
end
--endregion
--region Help
if string.find(msg, "I need help") then
if Heimdall_Data.config.minimapTagger.helpTTL == 0 then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Help TTL is 0, ignoring message: %s", ModuleName, msg))
end
return
end
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Found help alert in message: %s", ModuleName, msg))
end
local x, y = string.match(msg, "%((%d+%.%d+)%s*,%s*(%d+%.%d+)%)")
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Found help position: %s, %s", ModuleName, tostring(x), tostring(y)))
end
if x and y then
x, y = tonumber(x), tonumber(y)
PlantHelp(x, y, 1, doTag)
---@diagnostic disable-next-line: undefined-global
if TomTom then
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Adding help waypoint to TomTom", ModuleName))
end
local areaId = string.match(msg, "%[(%d+)%]") or 0
if areaId then areaId = tonumber(areaId) end
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] Area ID: %s", ModuleName, tostring(areaId)))
end
---@diagnostic disable-next-line: undefined-global
TomTom:AddMFWaypoint(areaId, nil, x / 100, y / 100, {
title = "Help " .. sender,
world = true,
from = "Heimdall",
crazy = true,
})
else
if Heimdall_Data.config.minimapTagger.debug then
print(string.format("[%s] No tomtom no waypoint", ModuleName))
end
end
end
end
--endregion
end)
print("[Heimdall] MinimapTagger loaded")
end,
}