local myname , ns = ...
local core = LibStub ( " AceAddon-3.0 " ) : GetAddon ( " SilverDragon " )
local module = core : NewModule ( " Announce " , " AceTimer-3.0 " , " LibSink-2.0 " )
local Debug = core.Debug
local LSM = LibStub ( " LibSharedMedia-3.0 " )
-- testing snippet:
-- /script C_Timer.After(2, function() SilverDragon:GetModule("Announce"):Seen("_", 32491, 120, 0.490, 0.362, false, "fake") end)
-- Register some media
LSM : Register ( " sound " , " Rubber Ducky " , 566121 )
LSM : Register ( " sound " , " Cartoon FX " , 566543 )
LSM : Register ( " sound " , " Explosion " , 566982 )
LSM : Register ( " sound " , " Shing! " , 566240 )
LSM : Register ( " sound " , " Wham! " , 566946 )
LSM : Register ( " sound " , " Simon Chime " , 566076 )
LSM : Register ( " sound " , " War Drums " , 567275 ) --NPC Scan default
LSM : Register ( " sound " , " Scourge Horn " , 567386 ) --NPC Scan default
LSM : Register ( " sound " , " Dwarf Horn " , 566064 )
LSM : Register ( " sound " , " Pygmy Drums " , 566508 )
LSM : Register ( " sound " , " Cheer " , 567283 )
LSM : Register ( " sound " , " Humm " , 569518 )
LSM : Register ( " sound " , " Short Circuit " , 568975 )
LSM : Register ( " sound " , " Fel Portal " , 569215 )
LSM : Register ( " sound " , " Fel Nova " , 568582 )
LSM : Register ( " sound " , " PVP Flag " , 569200 )
LSM : Register ( " sound " , " PvP Flag Horde " , 568165 ) -- PVPFlagTakenHorde
LSM : Register ( " sound " , " Thunder crack " , 566202 ) -- doodad/fx_thundercrack04.ogg
LSM : Register ( " sound " , " Algalon: Beware! " , 543587 )
LSM : Register ( " sound " , " Yogg Saron: Laugh " , 564859 )
LSM : Register ( " sound " , " Illidan: Not Prepared " , 552503 )
LSM : Register ( " sound " , " Magtheridon: I am Unleashed " , 554554 )
LSM : Register ( " sound " , " Loatheb: I see you " , 554236 )
LSM : Register ( " sound " , " Ikiss: Trinkets " , 561403 )
LSM : Register ( " sound " , " NPCScan " , 567275 ) --Sound file is actually bogus, this just forces the option NPCScan into menu. We hack it later.
LSM : Register ( " sound " , " PvP Alliance " , 568320 ) -- PVPWarningAllianceLong
LSM : Register ( " sound " , " PvP Horde " , 569112 ) -- PVPWarningHordeLong
LSM : Register ( " sound " , " Grimrail Train Horn " , 1023633 )
LSM : Register ( " sound " , " Squire Horn " , 598079 )
LSM : Register ( " sound " , " Gruntling Horn " , 598196 )
function module : OnInitialize ( )
self.db = core.db : RegisterNamespace ( " Announce " , {
profile = {
sink = true ,
drums = true ,
sound = true ,
soundgroup = true ,
soundguild = false ,
sound_mount = true ,
sound_boss = true ,
sound_loot = true ,
soundfile = " Loatheb: I see you " ,
soundfile_mount = " Illidan: Not Prepared " ,
soundfile_boss = " Magtheridon: I am Unleashed " ,
soundfile_loot = " Ikiss: Trinkets " ,
sound_loop = 1 ,
sound_mount_loop = 1 ,
sound_boss_loop = 1 ,
sound_loot_loop = 1 ,
flash = true ,
flash_texture = " Blizzard Low Health " ,
flash_color = { r = 1 , g = 0 , b = 1 , a = 1 , } ,
flash_mount = true ,
flash_texture_mount = " Blizzard Low Health " ,
flash_color_mount = { r = 0 , g = 1 , b = 0 , a = 1 , } ,
flash_boss = false ,
flash_texture_boss = " Blizzard Low Health " ,
flash_color_boss = { r = 1 , g = 0 , b = 1 , a = 1 , } ,
vibrate = true ,
vibrate_type = " High " ,
vibrate_intensity = 1 ,
vibrate_mount = true ,
vibrate_type_mount = " Low " ,
vibrate_intensity_mount = 1 ,
vibrate_boss = true ,
vibrate_type_boss = " High " ,
vibrate_intensity_boss = 1 ,
vibrate_loot = true ,
vibrate_type_loot = " High " ,
vibrate_intensity_loot = 0.8 ,
instances = false ,
dead = true ,
already = false ,
already_drop = true ,
already_transmog = false ,
already_alt = true ,
sink_opts = { } ,
channel = " Master " ,
unmute = false ,
background = false ,
loot = true ,
known_mounts = true ,
} ,
} )
self : SetSinkStorage ( self.db . profile.sink_opts )
if self.db . profile.sink_opts . sink20OutputSink == " Channel " then
-- 8.2.5 / Classic removed the ability to output to channels, outside of hardware-driven events
self.db . profile.sink_opts . sink20OutputSink = " Default "
end
core.RegisterCallback ( self , " Seen " )
core.RegisterCallback ( self , " SeenLoot " )
local config = core : GetModule ( " Config " , true )
if config then
local toggle = config.toggle
local get = function ( info ) return self.db . profile [ info [ # info ] ] end
local set = function ( info , v ) self.db . profile [ info [ # info ] ] = v end
local sink_config = self : GetSinkAce3OptionsDataTable ( )
local sink_args = { }
for k , v in pairs ( sink_config.args ) do
if k ~= " Channel " then
sink_args [ k ] = v
end
end
sink_config.args = sink_args
sink_config.inline = true
sink_config.order = 15
sink_config.args . Channel = nil
local faker = function ( id , name , zone , x , y )
return {
type = " execute " , name = name ,
desc = " Fake seeing " .. name ,
func = function ( )
-- id, zone, x, y, is_dead, source, unit
core.events : Fire ( " Seen " , id , zone , x , y , false , " fake " , false )
end ,
}
end
local soundfile = function ( enabled_key , order )
return {
type = " select " , dialogControl = " LSM30_Sound " ,
name = " Sound to Play " , desc = " Choose a sound file to play " ,
values = AceGUIWidgetLSMlists.sound ,
disabled = function ( ) return not self.db . profile [ enabled_key ] end ,
order = order ,
}
end
local soundrange = function ( order )
return {
type = " range " ,
name = " Repeat... " ,
desc = " How many times to repeat the sound " ,
min = 1 , max = 10 , step = 1 ,
order = order ,
}
end
local colorget = function ( info )
local color = self.db . profile [ info [ # info ] ]
return color.r , color.g , color.b , color.a
end
local colorset = function ( info , r , g , b , a )
local color = self.db . profile [ info [ # info ] ]
color.r , color.g , color.b , color.a = r , g , b , a
end
local fake_args = {
-- this is a vanilla mob
deathmaw = faker ( 10077 , " Deathmaw (Tame!) " , 29 , 0.5 , 0.5 ) ,
}
if LE_EXPANSION_LEVEL_CURRENT >= ( LE_EXPANSION_WRATH_OF_THE_LICH_KING or 999 ) then
fake_args.time = faker ( 32491 , " Time-Lost Proto Drake (Mount!) " , 120 , 0.490 , 0.362 )
fake_args.vyragosa = faker ( 32630 , " Vyragosa (Boring) " , 120 , 0.5 , 0.5 )
end
if not ns.CLASSIC then
-- id, name, zone, x, y, is_dead, is_new_location, source, unit
-- ishak = faker(157134, "Ishak of the Four Winds (Mount!)", 1527, 0.73, 0.83)
fake_args.anger = faker ( 60491 , " Sha of Anger (Boss!) " , 809 , 0.5 , 0.5 )
-- haakun = faker(83008, "Haakun", 946, 0.5, 0.5)
fake_args.yiphrim = faker ( 157473 , " Yiphrim the Will Ravager (Toy!) " , 1527 , 0.5 , 0.786 )
fake_args.amalgamation = faker ( 157593 , " Amalgamation of Flesh (Pet!) " , 1527 , 0.598 , 0.724 )
-- alash = faker(148787, "Alash'anir", 62, 0.598, 0.724)
-- burninator = faker(149141, "Burninator Mk V (Pet!)", 62, 0.414, 0.764)
fake_args.worldedge = faker ( 160821 , " Worldedge Gorger (mount) " , 1525 , 0.5 , 0.5 )
fake_args.tarahna = faker ( 126900 , " Instructor Tarahna (multi-toy) " , 882 , 0.5 , 0.5 )
fake_args.nerissa = faker ( 162690 , " Nerissa Heartless (mount) " , 1536 , 0.5 , 0.5 )
-- faeflayer = faker(171688, "Faeflayer", 1536, 0.5, 0.5)
fake_args.scrapking = faker ( 151625 , " Scrap King (loot) " , 1462 , 0.5 , 0.5 )
fake_args.kash = faker ( 159105 , " Collector Kash (lots of loot) " , 1536 , 0.5 , 0.5 )
-- worldcracker = faker(180032, "Wild Worldcracker", 1961, 0.5, 0.5)
-- blanchy = faker(173468, "Dead Blanchy", 1525, 0.5, 0.5)
fake_args.chest = {
type = " execute " , name = " Waterlogged Chest " ,
desc = " Fake seeing a Waterlogged Chest " ,
func = function ( )
-- id, zone, x, y, instanceid
core.events : Fire ( " SeenLoot " , " Waterlogged Chest " , 3341 , 37 , 0.318 , 0.628 )
end
}
fake_args.mount_chest = {
type = " execute " , name = " Mawsworn Supply Chest (mount) " ,
desc = " Fake seeing a Mawsworn Supply Chest, which contains a mount " ,
func = function ( )
-- id, zone, x, y, instanceid
core.events : Fire ( " SeenLoot " , " Mawsworn Supply Chest " , 4969 , 1970 , 0.318 , 0.628 )
end
}
end
local options = {
general = {
type = " group " , name = " Announcements " , inline = true ,
order = 10 ,
get = get , set = set ,
args = {
already = toggle ( " Already found " , " Announce when we see rares we've already killed / achieved (if known) " , 0 ) ,
already_drop = toggle ( " Got the loot " , " Still announce when we see rares which drop a mount / toy / pet you already have " , 10 ) ,
already_transmog = toggle ( " ...include transmog as loot " , " Count transmog appearances as knowable loot " , 11 ) ,
already_alt = toggle ( " Completed by an alt " , " Announce when we see rares for an achievement that the current character doesn't have, but an alt has completed already " , 20 ) ,
known_mounts = toggle ( " Known mounts are boring " , " Treat mount-dropping rares whose mount you already know as if they're regular rares (unless the mount is BoE) " , 25 ) ,
dead = toggle ( " Dead rares " , " Announce when we see dead rares, if known. Not all scanning methods know whether a rare is dead or not " , 30 ) ,
instances = toggle ( " Instances " , " Show announcements while in an instance " , 50 ) ,
loot = toggle ( " Treasures " , " Show announcements when treasure appears on the minimap " , 60 ) ,
} ,
} ,
message = {
type = " group " , name = " Messages " ,
order = 20 ,
get = get , set = set ,
args = {
sink = toggle ( " Enabled " , " Send a message to whatever scrolling text addon you're using. " , 10 ) ,
output = sink_config ,
} ,
} ,
test = {
type = " group " , name = " Test it! " ,
inline = true ,
args = fake_args ,
} ,
sound = {
type = " group " , name = " Sounds " ,
get = get , set = set ,
order = 10 ,
args = {
about = config.desc ( " Play sounds to announce rare mobs? Can do special things for special mobs. You *really* don't want to miss, say, the Time-Lost Proto Drake, after all... " , 0 ) ,
channel = {
type = " select " ,
name = _G.SOUND_CHANNELS or _G.AUDIO_CHANNELS , -- dragonflight
descStyle = " inline " ,
values = {
Ambience = _G.AMBIENCE_VOLUME ,
Master = _G.MASTER ,
Music = _G.MUSIC_VOLUME ,
SFX = _G.SOUND_VOLUME ,
Dialog = _G.DIALOG_VOLUME ,
} ,
order = 11 ,
} ,
unmute = toggle ( " Ignore mute " , " Play sounds even when muted " , 12 ) ,
background = toggle ( _G.ENABLE_BGSOUND , _G.OPTION_TOOLTIP_ENABLE_BGSOUND , 13 ) ,
drums = toggle ( " The Sound of Drums " , " Underneath it all, the constant drumming " , 14 ) ,
soundgroup = toggle ( " Group Sync Sounds " , " Play sounds from synced mobs from party/raid members " , 15 ) ,
soundguild = toggle ( " Guild Sync Sounds " , " Play sounds from synced mobs from guild members not in group " , 16 ) ,
regular = { type = " header " , name = " " , order = 20 , } ,
sound = toggle ( " Sounds " , " Play sounds for regular mobs " , 21 ) ,
soundfile = soundfile ( " sound " , 22 ) ,
sound_loop = soundrange ( 23 ) ,
mount = { type = " header " , name = " " , order = 25 , } ,
sound_mount = toggle ( " Mount sounds " , " Play a sound for mobs that drop a mount " , 26 ) ,
soundfile_mount = soundfile ( " sound_mount " , 27 ) ,
sound_mount_loop = soundrange ( 28 ) ,
boss = { type = " header " , name = " " , order = 30 , } ,
sound_boss = toggle ( " Boss sounds " , " Play a sound for mobs that require a group " , 31 ) ,
soundfile_boss = soundfile ( " sound_boss " , 35 ) ,
sound_boss_loop = soundrange ( 37 ) ,
loot = { type = " header " , name = " " , order = 40 , } ,
sound_loot = toggle ( " Loot sounds " , " Play a sound for treasures " , 41 ) ,
soundfile_loot = soundfile ( " sound_loot " , 45 ) ,
sound_loot_loop = soundrange ( 47 ) ,
} ,
} ,
flash = {
type = " group " , name = " Flash " ,
get = get , set = set ,
order = 15 ,
args = {
about = config.desc ( " Flash the screen when a rare is seen. " , 0 ) ,
flash = toggle ( " Enabled " , " Flash the screen? " , 1 ) ,
flash_color = {
name = COLOR ,
type = " color " ,
hasAlpha = true ,
descStyle = " inline " ,
get = colorget ,
set = colorset ,
order = 2 ,
} ,
flash_texture = {
name = TEXTURES_SUBHEADER ,
type = " select " ,
descStyle = " inline " ,
dialogControl = " LSM30_Background " ,
values = AceGUIWidgetLSMlists.background ,
order = 3 ,
} ,
preview = {
name = PREVIEW ,
type = " execute " ,
func = function ( )
module : Flash ( 50065 ) -- Armagedillo
end ,
order = 4 ,
} ,
mount = { type = " header " , name = " " , order = 10 , } ,
flash_mount = toggle ( " Mount flash " , " Flash the screen differently when we see a mob with a mount? " , 11 ) ,
flash_color_mount = {
name = COLOR ,
type = " color " ,
hasAlpha = true ,
descStyle = " inline " ,
get = colorget ,
set = colorset ,
order = 12 ,
} ,
flash_texture_mount = {
name = TEXTURES_SUBHEADER ,
type = " select " ,
descStyle = " inline " ,
dialogControl = " LSM30_Background " ,
values = AceGUIWidgetLSMlists.background ,
order = 13 ,
} ,
preview_mount = {
name = PREVIEW ,
type = " execute " ,
func = function ( )
module : Flash ( 32491 ) -- time lost
end ,
order = 14 ,
} ,
boss = { type = " header " , name = " " , order = 20 , } ,
flash_boss = toggle ( " Boss flash " , " Flash the screen differently when we see a boss rare? " , 21 ) ,
flash_color_boss = {
name = COLOR ,
type = " color " ,
hasAlpha = true ,
descStyle = " inline " ,
get = colorget ,
set = colorset ,
order = 22 ,
} ,
flash_texture_boss = {
name = TEXTURES_SUBHEADER ,
type = " select " ,
descStyle = " inline " ,
dialogControl = " LSM30_Background " ,
values = AceGUIWidgetLSMlists.background ,
order = 23 ,
} ,
preview_boss = {
name = PREVIEW ,
type = " execute " ,
func = function ( )
module : Flash ( 70096 ) -- War-God Dokah
end ,
order = 24 ,
} ,
} ,
} ,
controller = {
type = " group " , name = " Controller " ,
get = get , set = set ,
disabled = function ( info ) return info [ # info ] ~= " controller " and not C_GamePad.IsEnabled ( ) end ,
order = 15 ,
args = {
about = config.desc ( " Vibrate a connected controller when a rare is seen. Only works if controller support is enabled. You can turn it on by typing `/console GamePadEnable 1` in the chat box. " , 0 ) ,
} ,
} ,
}
local function vibrate_section ( t , key , order , heading )
key = key and ( " _ " .. key ) or " "
if heading then
t [ " vibrate_heading " .. key ] = { type = " header " , name = " " , order = order , }
end
t [ " vibrate " .. key ] = toggle ( heading or " Vibrate " , " Vibrate the controller? " , order + 1 )
t [ " vibrate_type " .. key ] = {
type = " select " , name = " Type " ,
desc = " What type of vibration to use " ,
values = {
Low = " Low " ,
High = " High " ,
LTrigger = " LTrigger (PS5 only) " ,
RTrigger = " RTrigger (PS5 only) " ,
} ,
order = order + 2 ,
}
t [ " vibrate_intensity " .. key ] = {
type = " range " , name = " Intensity " ,
desc = " How strong the vibration should be " ,
min = 0 , max = 1 , step = 0.1 ,
order = order + 3 ,
}
t [ " preview " .. key ] = {
type = " execute " , name = PREVIEW ,
func = function ( info )
C_GamePad.SetVibration ( self.db . profile [ " vibrate_type " .. key ] , self.db . profile [ " vibrate_intensity " .. key ] )
end ,
order = order + 4 ,
}
return order + 5
end
local order = 1
order = vibrate_section ( options.controller . args , nil , 1 )
order = vibrate_section ( options.controller . args , " mount " , order , " Vibrate for mounts " )
order = vibrate_section ( options.controller . args , " boss " , order , " Vibrate for bosses " )
order = vibrate_section ( options.controller . args , " loot " , order , " Vibrate for loot " )
config.options . args.general . plugins.announce = options
end
end
function module : HasInterestingMounts ( id , isloot )
if not module.db . profile.known_mounts then
return ns.Loot . HasMounts ( id , nil , nil , isloot )
end
return ns.Loot . HasInterestingMounts ( id , isloot )
end
function module : Seen ( callback , id , zone , x , y , is_dead , source , ... )
Debug ( " Announce:Seen " , id , zone , x , y , is_dead , ... )
if not self.db . profile.instances and IsInInstance ( ) then
return
end
if not self : ShouldAnnounce ( id , zone , x , y , is_dead , source , ... ) then
return
end
core.events : Fire ( " Announce " , id , zone , x , y , is_dead , source , ... )
end
function module : SeenLoot ( callback , name , id , zone , x , y , ... )
Debug ( " Announce:SeenLoot " , name , id , zone , x , y , ... )
if not self.db . profile.instances and IsInInstance ( ) then
return
end
if not self.db . profile.loot then
return
end
core.events : Fire ( " AnnounceLoot " , name , id , zone , x , y , ... )
end
function module : ShouldAnnounce ( id , zone , x , y , is_dead , source , ... )
if is_dead and not self.db . profile.dead then
Debug ( " ShouldAnnounce " , false , " dead " )
return false
end
if core.db . global.always [ id ] then
-- If you've manually added a mob, bypass any other checks
Debug ( " ShouldAnnounce " , true , " always " )
return true
end
if not self.db . profile.already_drop and ns.Loot . Status ( id , self.db . profile.already_transmog ) == true and not ns.Loot . HasMounts ( id , true , true ) then
-- hide mobs which have a mount/pet/toy which you already own... apart from BoE mounts
-- this means there's knowable loot, and it's all known
Debug ( " ShouldAnnounce " , false , " already got loot " )
return false
end
if ns.mobdb [ id ] and (
( ns.mobdb [ id ] . requires and not ns.conditions . check ( ns.mobdb [ id ] . requires ) ) or
( ns.mobdb [ id ] . active and not ns.conditions . check ( ns.mobdb [ id ] . active ) )
) then
Debug ( " ShouldAnnounce " , false , " requirements not met " )
return false
end
if not self.db . profile.already then
-- hide already-completed mobs
local quest , achievement , by_alt = ns : CompletionStatus ( id )
if by_alt and not self.db . profile.already_alt then
-- an alt has completed the achievement, and we don't want to know about that
Debug ( " ShouldAnnounce " , false , " alt got achievement " )
return false
end
if source == " vignette " or source == " point-of-interest " then
-- The vignette's presence implies no quest completion
Debug ( " ShouldAnnounce " , true , " vignette implies quest " )
return true
end
if quest ~= nil then
Debug ( " ShouldAnnounce " , not quest , " quest " )
return not quest
end
if achievement ~= nil then
-- can just fall back on achievement
Debug ( " ShouldAnnounce " , not achievement , " achievement " )
return not achievement
end
end
Debug ( " ShouldAnnounce " , true , " fallback " )
return true
end
core.RegisterCallback ( " SD Announce Sink " , " Announce " , function ( callback , id , zone , x , y , dead , source )
if not module.db . profile.sink then
return
end
Debug ( " Pouring " )
if source : match ( " ^sync " ) then
local channel , player = source : match ( " sync:(.+):(.+) " )
if channel and player then
local localized_zone = core.zone_names [ zone ] or UNKNOWN
source = " by " .. player .. " in your " .. strlower ( channel ) .. " ; " .. localized_zone
end
end
local pin = " "
if x and y then
if x == 0 and y == 0 then
source = source .. " @ unknown location "
else
source = source .. ( " @ %.1f, %.1f " ) : format ( x * 100 , y * 100 )
if module.db . profile.sink_opts . sink20OutputSink == " ChatFrame " and MAP_PIN_HYPERLINK then
pin = ( " |cffffff00|Hworldmap:%d:%d:%d|h[%s]|h|r " ) : format (
zone , x * 10000 , y * 10000 , MAP_PIN_HYPERLINK
)
end
end
end
module : Pour ( ( " Rare seen: %s%s (%s)%s " ) : format ( core : GetMobLabel ( id ) , dead and " ... but it's dead " or ' ' , source or ' ' , pin ) )
end )
core.RegisterCallback ( " SD AnnounceLoot Sink " , " AnnounceLoot " , function ( callback , name , id , zone , x , y , instanceid )
if not module.db . profile.sink then
return
end
Debug ( " Pouring " )
local pin = " "
local location = UNKNOWN
if x and y and x > 0 and y > 0 then
location = ( " %.1f, %.1f " ) : format ( x * 100 , y * 100 )
if module.db . profile.sink_opts . sink20OutputSink == " ChatFrame " and MAP_PIN_HYPERLINK then
pin = ( " |cffffff00|Hworldmap:%d:%d:%d|h[%s]|h|r " ) : format (
zone , x * 10000 , y * 10000 , MAP_PIN_HYPERLINK
)
end
end
module : Pour ( ( " Treasure seen: %s (%s)%s " ) : format ( name , location , pin ) )
end )
local cvar_overrides
local channel_cvars = {
Ambience = " Sound_EnableAmbience " ,
Master = " Sound_EnableAllSound " ,
Music = " Sound_EnableMusic " ,
SFX = " Sound_EnableSFX " ,
Dialog = " Sound_EnableDialog " ,
}
local delays = {
[ " Ikiss: Trinkets " ] = 5.7 ,
}
local nowplaying
function module : PlaySound ( s )
-- Arg is a table, to make scheduling the loops easier. I am lazy.
Debug ( " Playing sound " , s.soundfile , s.loops )
-- boring check:
if s and s.handle then
StopSound ( s.handle )
if s.drumshandle then
StopSound ( s.drumshandle )
end
s.handle = nil
s.drumshandle = nil
end
if not s.loops or s.loops == 0 then
if cvar_overrides and s.cvars then
for cvar , value in pairs ( s.cvars ) do
SetCVar ( cvar , value )
end
cvar_overrides = false
end
nowplaying = false
return
end
if not cvar_overrides then
if self.db . profile.background and GetCVar ( " Sound_EnableSoundWhenGameIsInBG " ) == " 0 " then
cvar_overrides = true
s.cvars = s.cvars or { }
s.cvars [ " Sound_EnableSoundWhenGameIsInBG " ] = GetCVar ( " Sound_EnableSoundWhenGameIsInBG " )
SetCVar ( " Sound_EnableSoundWhenGameIsInBG " , " 1 " )
end
if self.db . profile.unmute and GetCVar ( channel_cvars [ self.db . profile.channel ] ) == " 0 " then
cvar_overrides = true
s.cvars = s.cvars or { }
s.cvars [ channel_cvars [ self.db . profile.channel ] ] = GetCVar ( channel_cvars [ self.db . profile.channel ] )
SetCVar ( channel_cvars [ self.db . profile.channel ] , " 1 " )
end
end
-- now, noise!
local drums = self.db . profile.drums
if s.soundfile == " NPCScan " then
--Override default behavior and force npcscan behavior of two sounds at once
drums = true
local _ , handle = PlaySoundFile ( LSM : Fetch ( " sound " , " Scourge Horn " ) , self.db . profile.channel )
s.handle = handle
else
--Play whatever sound is set
local _ , handle = PlaySoundFile ( LSM : Fetch ( " sound " , s.soundfile ) , self.db . profile.channel )
s.handle = handle
end
if drums then
local _ , handle = PlaySoundFile ( LSM : Fetch ( " sound " , " War Drums " ) , self.db . profile.channel )
s.drumshandle = handle
end
s.loops = s.loops - 1
-- we guarantee one callback, in case we need to do cleanup
self : ScheduleTimer ( " PlaySound " , delays [ s.soundfile ] or 4.5 , s )
nowplaying = true
end
core.RegisterCallback ( " SD Announce Sound " , " Announce " , function ( callback , id , zone , x , y , dead , source )
if not LSM then return end
if nowplaying then return end
if source : match ( " ^sync " ) then
local channel , player = source : match ( " sync:(.+):(.+) " )
if channel == " GUILD " and not module.db . profile.soundguild or ( channel == " PARTY " or channel == " RAID " ) and not module.db . profile.soundgroup then return end
end
local soundfile , loops
if module : HasInterestingMounts ( id ) then
if not module.db . profile.sound_mount then return end
soundfile = module.db . profile.soundfile_mount
loops = module.db . profile.sound_mount_loop
elseif ns.mobdb [ id ] and ns.mobdb [ id ] . boss then
if not module.db . profile.sound_boss then return end
soundfile = module.db . profile.soundfile_boss
loops = module.db . profile.sound_boss_loop
else
if not module.db . profile.sound then return end
soundfile = module.db . profile.soundfile
loops = module.db . profile.sound_loop
end
module : PlaySound { soundfile = soundfile , loops = loops }
end )
core.RegisterCallback ( " SD AnnounceLoot Sound " , " AnnounceLoot " , function ( callback , name , id , zone , x , y , instanceid )
if not ( module.db . profile.sound_loot and LSM ) then
return
end
if nowplaying then return end
local soundfile , loops
if module : HasInterestingMounts ( id , true ) then
if not module.db . profile.sound_mount then return end
soundfile = module.db . profile.soundfile_mount
loops = module.db . profile.sound_mount_loop
else
soundfile = module.db . profile.soundfile_loot
loops = module.db . profile.sound_loot_loop
end
module : PlaySound { soundfile = soundfile , loops = loops }
end )
do
local flashframe
function module : Flash ( id , isloot )
if not module.db . profile.flash then
return
end
if not flashframe then
flashframe = CreateFrame ( " Frame " , nil , WorldFrame )
flashframe : SetClampedToScreen ( true )
flashframe : SetFrameStrata ( " FULLSCREEN_DIALOG " )
flashframe : SetToplevel ( true )
flashframe : SetAllPoints ( UIParent )
flashframe : Hide ( )
-- Use the OutOfControl (blue) and LowHealth (red) textures to get a purple flash
local texture = flashframe : CreateTexture ( nil , " BACKGROUND " )
texture : SetBlendMode ( " ADD " )
texture : SetDesaturated ( true )
texture : SetAllPoints ( )
local group = flashframe : CreateAnimationGroup ( )
group : SetLooping ( " BOUNCE " )
local pulse = group : CreateAnimation ( " Alpha " )
pulse : SetFromAlpha ( 0.3 )
pulse : SetToAlpha ( 0.75 )
pulse : SetDuration ( 0.5236 )
local loops = 0
group : SetScript ( " OnLoop " , function ( frame , state )
loops = loops + 1
if loops == 9 then
group : Finish ( )
end
end )
group : SetScript ( " OnFinished " , function ( self )
loops = 0
flashframe : Hide ( )
end )
flashframe : SetScript ( " OnShow " , function ( self )
local background = module.db . profile.flash_texture
local color = module.db . profile.flash_color
if self.id and ns.mobdb [ self.id ] then
if module.db . profile.flash_mount and module : HasInterestingMounts ( id , isloot ) then
background = module.db . profile.flash_texture_mount
color = module.db . profile.flash_color_mount
elseif ns.mobdb [ self.id ] . boss and module.db . profile.flash_boss then
background = module.db . profile.flash_texture_boss
color = module.db . profile.flash_color_boss
end
end
texture : SetTexture ( LSM : Fetch ( " background " , background ) )
texture : SetVertexColor ( color.r , color.g , color.b , color.a )
group : Play ( )
end )
end
Debug ( " Flashing " )
flashframe.id = id
flashframe : Hide ( )
flashframe : Show ( )
end
core.RegisterCallback ( " SD Announce Flash " , " Announce " , function ( callback , id )
module : Flash ( id )
end )
core.RegisterCallback ( " SD AnnounceLoot Flash " , " AnnounceLoot " , function ( callback , name , id )
module : Flash ( id , true )
end )
end
core.RegisterCallback ( " SD Announce Controller " , " Announce " , function ( callback , id , zone , x , y , dead , source )
local vibrate_type , vibrate_intensity
if module : HasInterestingMounts ( id ) then
if not module.db . profile.vibrate_mount then return end
vibrate_type = module.db . profile.vibrate_type_mount
vibrate_intensity = module.db . profile.vibrate_intensity_mount
elseif ns.mobdb [ id ] and ns.mobdb [ id ] . boss then
if not module.db . profile.vibrate_boss then return end
vibrate_type = module.db . profile.vibrate_type_boss
vibrate_intensity = module.db . profile.vibrate_intensity_boss
else
if not module.db . profile.vibrate then return end
vibrate_type = module.db . profile.vibrate_type
vibrate_intensity = module.db . profile.vibrate_intensity
end
C_GamePad.SetVibration ( vibrate_type , vibrate_intensity )
end )
core.RegisterCallback ( " SD AnnounceLoot Controller " , " AnnounceLoot " , function ( callback , name , id , zone , x , y , instanceid )
if not module.db . profile.vibrate_loot then
return
end
C_GamePad.SetVibration ( module.db . profile.vibrate_type_loot , module.db . profile.vibrate_intensity_loot )
end )