You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
306 lines
12 KiB
306 lines
12 KiB
local myname, ns = ...
|
|
|
|
local core = LibStub("AceAddon-3.0"):GetAddon("SilverDragon")
|
|
local module = core:NewModule("Scan_Vignettes", "AceEvent-3.0", "AceConsole-3.0")
|
|
local Debug = core.Debug
|
|
|
|
local HBD = LibStub("HereBeDragons-2.0")
|
|
|
|
local function vignetteToggle(vignetteid, name)
|
|
return {
|
|
type = "toggle",
|
|
name = name,
|
|
desc = "ID: " .. vignetteid,
|
|
arg = vignetteid,
|
|
-- width = "double",
|
|
descStyle = "inline",
|
|
order = vignetteid,
|
|
}
|
|
end
|
|
|
|
function module:OnInitialize()
|
|
self.db = core.db:RegisterNamespace("Scan_Vignettes", {
|
|
profile = {
|
|
enabled = true,
|
|
pointsofinterest = true,
|
|
visibleOnly = false,
|
|
zoneInfinite = true,
|
|
ignore = {
|
|
-- [id] = "name",
|
|
},
|
|
ignore_type = {
|
|
-- [atlas:lower()] = true
|
|
},
|
|
},
|
|
})
|
|
|
|
self.compat_disabled = (LE_EXPANSION_LEVEL_CURRENT < (LE_EXPANSION_MISTS_OF_PANDARIA or 999)) -- missing on classic_era
|
|
|
|
-- migrate!
|
|
local db = self.db.profile
|
|
if db.loot == false then
|
|
db.ignore_type.vignetteloot = true
|
|
db.ignore_type.vignettelootelite = true
|
|
db.loot = nil
|
|
end
|
|
|
|
local config = core:GetModule("Config", true)
|
|
if config then
|
|
config.options.args.scanning.plugins.vignettes = {
|
|
vignettes = {
|
|
type = "group",
|
|
name = "Vignettes",
|
|
get = function(info) return self.db.profile[info[#info]] end,
|
|
set = function(info, v) self.db.profile[info[#info]] = v end,
|
|
args = {
|
|
enabled = config.toggle("Enabled", "Scan minimap vignettes (it's what Blizzard calls them, okay?)", 10),
|
|
pointsofinterest = config.toggle("World points-of-interest", "Show alerts for point of interest vignettes added to world map itself", 20),
|
|
zoneInfinite = config.toggle("Infinite distance vignettes", "Show alerts for vignettes that can be seen from across the entire zone (this can get really spammy in some zones)", 25),
|
|
visibleOnly = config.toggle("Wait until visible", "Don't notify until the vignette is actually visible on the minimap", 30),
|
|
ignore = {
|
|
type="group",
|
|
name=IGNORE,
|
|
args={
|
|
desc = config.desc("These lists will fill in as vignettes are announced. Check a box, and we'll remember to never announce that specific vignette again.", 0),
|
|
type = {
|
|
type = "multiselect",
|
|
name = "Types",
|
|
get = function(info, key) return self.db.profile.ignore_type[key] end,
|
|
set = function(info, key, value)
|
|
self.db.profile.ignore_type[key] = value
|
|
end,
|
|
values = {
|
|
vignettekill = CreateAtlasMarkup("vignettekill", 20, 20) .. " Kill",
|
|
vignettekillelite = CreateAtlasMarkup("vignettekillelite", 24, 24) .. " Kill elite",
|
|
vignetteloot = CreateAtlasMarkup("vignetteloot", 20, 20) .. " Loot",
|
|
vignettelootelite = CreateAtlasMarkup("vignettelootelite", 24, 24) .. " Loot elite",
|
|
vignetteevent = CreateAtlasMarkup("vignetteevent", 20, 20) .. " Event",
|
|
vignetteeventelite = CreateAtlasMarkup("vignetteeventelite", 24, 24) .. " Event elite",
|
|
["warfront-neutralhero"] = CreateAtlasMarkup("warfront-neutralhero", 20, 20) .. " Bonus boss",
|
|
},
|
|
order=10,
|
|
},
|
|
specific = {
|
|
type="group",
|
|
name="Specific",
|
|
inline=true,
|
|
get=function(info) return self.db.profile.ignore[info.arg] end,
|
|
set=function(info, v) self.db.profile.ignore[info.arg] = v and info.option.name or nil end,
|
|
args={},
|
|
order=20,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
local vignettes = config.options.args.scanning.plugins.vignettes.vignettes.args.ignore.args.specific.args
|
|
for vignetteid, name in pairs(self.db.profile.ignore) do
|
|
vignettes['vignette:'..vignetteid] = vignetteToggle(vignetteid, name)
|
|
end
|
|
end
|
|
end
|
|
|
|
function module:OnEnable()
|
|
if self.compat_disabled then return end
|
|
self:RegisterEvent("VIGNETTE_MINIMAP_UPDATED")
|
|
self:RegisterEvent("VIGNETTES_UPDATED")
|
|
|
|
core.RegisterCallback(self, "SeenVignette")
|
|
end
|
|
|
|
function module:SeenVignette(event, name, vignetteid, atlas)
|
|
local config = core:GetModule("Config", true)
|
|
if not config then return end
|
|
local vignetteconfig = config.options.args.scanning.plugins.vignettes.vignettes.args.ignore.args.specific.args
|
|
if not vignetteconfig["vignette:"..vignetteid] then
|
|
vignetteconfig["vignette:"..vignetteid] = vignetteToggle(vignetteid, name)
|
|
end
|
|
local typeconfig = config.options.args.scanning.plugins.vignettes.vignettes.args.ignore.args.type.values
|
|
if not typeconfig[atlas:lower()] then
|
|
typeconfig[atlas:lower()] = CreateAtlasMarkup(atlas, 20, 20) .. " " .. atlas
|
|
end
|
|
end
|
|
|
|
-- handy debug command:
|
|
-- /dump C_VignetteInfo.GetVignetteInfo(C_VignetteInfo.GetVignettes()[1])
|
|
|
|
local already_notified = {
|
|
-- [instanceid] = true
|
|
}
|
|
local already_notified_loot = {
|
|
-- [vignetteid] = time()
|
|
}
|
|
|
|
local MOB = 1
|
|
local LOOT = 2
|
|
local visible_zonedeny = {
|
|
-- [1550] = LOOT, -- The Shadowlands, because of...
|
|
-- [1565] = LOOT, -- Ardenweald, where all chests are notified from the entire zone
|
|
-- But also all the Shadowlands zones, because callings quests are fucky about this and I need to work out a heuristic for them
|
|
-- [1533] = LOOT, -- Bastion
|
|
-- [1536] = LOOT, -- Maldraxxus
|
|
-- [1525] = LOOT, -- Revendreth
|
|
[1543] = true, -- Maw (where there's just so *many*)
|
|
}
|
|
local visible_noparents = {
|
|
[1961] = true, -- Korthia is a child of the Maw
|
|
}
|
|
local vignette_denylist = {
|
|
[637] = true, -- Garrison Cache
|
|
}
|
|
local function shouldShowNotVisible(vignetteInfo, zone)
|
|
local variant = (vignetteInfo.atlasName == "VignetteLoot" or vignetteInfo.atlasName == "VignetteLootElite") and LOOT or MOB
|
|
if vignetteInfo.onWorldMap and module.db.profile.pointsofinterest and variant == MOB then
|
|
-- If it's on the world map, it's cool
|
|
-- BUT don't alert for treasures on the world map, because there's no time-sensitive ones so far (9.1), and
|
|
-- it results in bursts of alerts when zoning into the Shadowlands area with the daily chests
|
|
return not module.db.profile.visibleOnly
|
|
end
|
|
if vignetteInfo.zoneInfiniteAOI and not module.db.profile.zoneInfinite then
|
|
-- It can be semi-seen from the entire zone, and so we should wait until it's actually-visible
|
|
return false
|
|
end
|
|
if visible_zonedeny[zone] == true or visible_zonedeny[zone] == variant then
|
|
return false
|
|
end
|
|
local info = C_Map.GetMapInfo(zone)
|
|
if not visible_noparents[zone] and info and info.parentMapID and info.parentMapID ~= 0 then
|
|
return shouldShowNotVisible(vignetteInfo, info.parentMapID)
|
|
end
|
|
return not module.db.profile.visibleOnly
|
|
end
|
|
|
|
function module:WorkOutMobFromVignette(instanceid)
|
|
if not self.db.profile.enabled then return end
|
|
if already_notified[instanceid] then
|
|
return --Debug("Skipping notify", "already done", instanceid)
|
|
end
|
|
if not core.db.profile.instances and IsInInstance() then return end
|
|
local vignetteInfo = C_VignetteInfo.GetVignetteInfo(instanceid)
|
|
if not vignetteInfo then
|
|
return -- Debug("vignette had no info")
|
|
end
|
|
if vignette_denylist[vignetteInfo.vignetteID or 0] then
|
|
return -- Debug("Vignette was on the denylist", vignetteInfo.vignetteID)
|
|
end
|
|
if self.db.profile.ignore[vignetteInfo.vignetteID] then
|
|
return -- Debug("Vignette was ignored", vignetteInfo.vignetteID, vignetteInfo.name)
|
|
end
|
|
if self.db.profile.ignore_type[vignetteInfo.atlasName:lower()] then
|
|
return -- Debug("Vignette type not enabled", vignetteInfo.atlasName, vignetteInfo.vignetteID, vignetteInfo.name)
|
|
end
|
|
local current_zone = HBD:GetPlayerZone()
|
|
if not current_zone or current_zone == 0 then
|
|
return -- Debug("We don't know what zone we're in", current_zone)
|
|
end
|
|
local source = vignetteInfo.onWorldMap and "point-of-interest" or "vignette"
|
|
local x, y
|
|
if vignetteInfo.vignetteGUID then
|
|
local position = C_VignetteInfo.GetVignettePosition(vignetteInfo.vignetteGUID, current_zone)
|
|
if position then
|
|
x, y = position:GetXY()
|
|
end
|
|
end
|
|
if not vignetteInfo.onMinimap and not shouldShowNotVisible(vignetteInfo, current_zone) then
|
|
return -- Debug("vignette not visible on minimap and we're only alerting for visibles")
|
|
end
|
|
if vignetteInfo.atlasName == "VignetteLoot" or vignetteInfo.atlasName == "VignetteLootElite" then
|
|
if not core:PlayerIsInteractive() then
|
|
return -- Debug("skipping notification", "on taxi")
|
|
end
|
|
if already_notified_loot[vignetteInfo.vignetteGUID] and time() < (already_notified_loot[vignetteInfo.vignetteGUID] + core.db.profile.delay) then
|
|
return -- Debug("skipping notification", "delay not exceeded")
|
|
end
|
|
local treasure = ns.vignetteTreasureLookup[vignetteInfo.vignetteID]
|
|
if treasure then
|
|
if treasure.requires and not ns.conditions.check(treasure.requires) then
|
|
-- Debug("skipping notification", "vignette requirements not met", ns.conditions.summarize(treasure.requires))
|
|
return
|
|
end
|
|
if treasure.active and not ns.conditions.check(treasure.active) then
|
|
-- Debug("skipping notification", "vignette not active", ns.conditions.summarize(treasure.active))
|
|
return
|
|
end
|
|
end
|
|
already_notified_loot[vignetteInfo.vignetteGUID] = time()
|
|
core.events:Fire("SeenVignette", vignetteInfo.name, vignetteInfo.vignetteID, vignetteInfo.atlasName, current_zone, x or 0, y or 0, instanceid)
|
|
core.events:Fire("SeenLoot", vignetteInfo.name, vignetteInfo.vignetteID, current_zone, x or 0, y or 0, instanceid)
|
|
return true
|
|
end
|
|
if ns.vignetteTreasureLookup[vignetteInfo.vignetteID] and ns.vignetteTreasureLookup[vignetteInfo.vignetteID].hidden then
|
|
return -- Debug("skipping notification", "ignored by vignette-id")
|
|
end
|
|
if vignetteInfo.objectGUID then
|
|
-- this *may* be a mob, but it also may be something which you interact with to summon the mob
|
|
local mobid = ns.IdFromGuid(vignetteInfo.objectGUID)
|
|
if mobid and ns.mobdb[mobid] then
|
|
--Debug("mob from guid", vignetteInfo.objectGUID, mobid)
|
|
return self:NotifyIfNeeded(mobid, current_zone, x, y, source, instanceid)
|
|
end
|
|
end
|
|
-- And now, comparatively uncommon fallbacks:
|
|
if vignetteInfo.vignetteID and ns.vignetteMobLookup[vignetteInfo.vignetteID] then
|
|
-- IDs are based on https://bnet.marlam.in/dbc.php?dbc=vignette.db2
|
|
--Debug("vignetteMobLookup", vignetteInfo.name, vignetteInfo.vignetteID, ns.vignetteMobLookup[vignetteInfo.vignetteID])
|
|
return self:NotifyForMobs(ns.vignetteMobLookup[vignetteInfo.vignetteID], current_zone, x, y, source, instanceid)
|
|
end
|
|
if vignetteInfo.name then
|
|
local mobid = core:IdForMob(vignetteInfo.name)
|
|
if mobid then
|
|
--Debug("name", vignetteInfo.name, mobid)
|
|
return self:NotifyIfNeeded(mobid, current_zone, x, y, source, instanceid)
|
|
end
|
|
end
|
|
Debug("Couldn't work out mob from vignette", vignetteInfo.name)
|
|
end
|
|
function module:NotifyForMobs(mobs, ...)
|
|
for mobid in pairs(mobs) do
|
|
self:NotifyIfNeeded(mobid, ...)
|
|
end
|
|
end
|
|
|
|
function module:VIGNETTE_MINIMAP_UPDATED(event, instanceid, onMinimap, ...)
|
|
Debug("VIGNETTE_MINIMAP_UPDATED", instanceid, onMinimap, ...)
|
|
if not instanceid then
|
|
-- ...just in case
|
|
Debug("No Vignette instanceid")
|
|
return
|
|
end
|
|
self:WorkOutMobFromVignette(instanceid)
|
|
end
|
|
function module:VIGNETTES_UPDATED()
|
|
-- Debug("VIGNETTES_UPDATED")
|
|
local vignetteids = C_VignetteInfo.GetVignettes()
|
|
|
|
-- Interesting point: these show up here before they're on the minimap. This means that VIGNETTE_MINIMAP_UPDATED is actually almost never going to trip this notification now...
|
|
|
|
for i=1, #vignetteids do
|
|
self:WorkOutMobFromVignette(vignetteids[i])
|
|
end
|
|
end
|
|
|
|
function module:NotifyIfNeeded(id, current_zone, x, y, variant, instanceid)
|
|
if not (x and y) then
|
|
x, y = HBD:GetPlayerZonePosition()
|
|
end
|
|
if not (current_zone and x and y) then
|
|
return
|
|
end
|
|
local mob = ns.mobdb[id]
|
|
if mob then
|
|
if mob.requires and not ns.conditions.check(mob.requires) then
|
|
-- Debug("skipping notification", "mob requirements not met", ns.conditions.summarize(mob.requires))
|
|
return
|
|
end
|
|
if mob.active and not ns.conditions.check(mob.active) then
|
|
-- Debug("skipping notification", "mob not active", ns.conditions.summarize(mob.active))
|
|
return
|
|
end
|
|
end
|
|
already_notified[instanceid] = true
|
|
local vignetteInfo = C_VignetteInfo.GetVignetteInfo(instanceid)
|
|
local ret = core:NotifyForMob(id, current_zone, x, y, false, variant or "vignette", false, nil, false, instanceid)
|
|
core.events:Fire("SeenVignette", vignetteInfo.name, vignetteInfo.vignetteID, vignetteInfo.atlasName, current_zone, x, y, instanceid, id)
|
|
return ret
|
|
end
|
|
|