Compare commits
265 Commits
Author | SHA1 | Date | |
---|---|---|---|
e6525c6443 | |||
dfd2064a40 | |||
dfe5b94780 | |||
52246e2e16 | |||
4897a5b1a9 | |||
2381f68912 | |||
ad969e8604 | |||
31678f9a82 | |||
1785af4d9d | |||
69d7efe6f0 | |||
202c5d0f46 | |||
476e907205 | |||
724194abe2 | |||
d57b573683 | |||
5d8afe8db7 | |||
b14f1ff2f9 | |||
a1301abdb2 | |||
f897183920 | |||
c1885ce76a | |||
e676d53e97 | |||
f05156b257 | |||
c8f9d81b3e | |||
3a1639ab27 | |||
1da1e7bf9f | |||
304fbcbaae | |||
80f8500f6e | |||
78cbcbde9d | |||
![]() |
8db1cb179c | ||
a065e47545 | |||
5271029b84 | |||
7c4fb53baa | |||
1c2fb471a6 | |||
85f72b14e0 | |||
99261beb08 | |||
d34be4f18d | |||
3d26832e54 | |||
cd80c9fc0e | |||
672ca07782 | |||
b06313c4eb | |||
31be9b0ce8 | |||
d69a53b4c8 | |||
7aa5d50a6c | |||
d047c632ed | |||
9eb5c04a33 | |||
498432d968 | |||
e04eb57202 | |||
25fe8350a7 | |||
9a10386e65 | |||
75ab8646e8 | |||
37ef42e53d | |||
b2aa1b75f3 | |||
31bcd3481c | |||
966078c339 | |||
fdcd816235 | |||
054d8ab7ef | |||
0327359300 | |||
c61a4b0c04 | |||
950f95cef1 | |||
d40670fef6 | |||
d6e5e7941f | |||
a06e9027c6 | |||
8fb0595ef8 | |||
d3808a887e | |||
1ed379c23d | |||
0e66db1d8a | |||
bac16d22a9 | |||
8b4de82142 | |||
35930c52a4 | |||
293e71e619 | |||
7150189a0d | |||
0e951d7089 | |||
ef89c3001b | |||
b538c7b5de | |||
6c234e7fa4 | |||
407d8f2da2 | |||
9b755cd0be | |||
19f9d4bda9 | |||
de744337ad | |||
63ba6d2da1 | |||
79b77ee6c3 | |||
0e2935f844 | |||
0ad6a23daa | |||
35398ebf38 | |||
62b028cf56 | |||
ad676915bb | |||
61ebb22a85 | |||
8348b93b30 | |||
550e11b488 | |||
ed10ea496d | |||
6e5c7510d0 | |||
68d0393915 | |||
f1e07f0a3b | |||
90100f6f5b | |||
995966e952 | |||
a90eb8248f | |||
ffca28c67d | |||
20a2a95ce6 | |||
145fd02ba8 | |||
196a5a8cfa | |||
439e9b29d1 | |||
a3f1a0e96d | |||
c81e349e90 | |||
30068a5b11 | |||
036b6b23a8 | |||
128eb44003 | |||
0f72b2048e | |||
1e4045ab7a | |||
b871549087 | |||
58760831dc | |||
0a8ab00637 | |||
8396801d80 | |||
19af9894e5 | |||
7293f5a8fa | |||
9d12609147 | |||
2c7089504f | |||
8fbff23bee | |||
0c5078e3f3 | |||
d143a18838 | |||
ba889e442c | |||
4511ecbf0a | |||
fe37bebd2c | |||
d987436892 | |||
9f4e19104f | |||
c0568075e1 | |||
13415fb065 | |||
ca13d1e364 | |||
bf916dd8d5 | |||
4aa168ebcc | |||
2cea01f367 | |||
2ec0aea19c | |||
846584d6fe | |||
1b5912a1bf | |||
954dbfa425 | |||
42ec90a5df | |||
0b4350c8ae | |||
da28805882 | |||
6551e24069 | |||
28ef8cb33a | |||
d4b0dee037 | |||
799d3e1ddd | |||
e6f3bac946 | |||
05c7e71794 | |||
41b980d118 | |||
3efd99cdc8 | |||
119eb7965b | |||
f4421f0334 | |||
688f2f4b30 | |||
87300bf48a | |||
8cbad47acc | |||
241615238c | |||
319e6cdd77 | |||
d54e93ad85 | |||
efe0002e02 | |||
e58d92c399 | |||
fa18138c3b | |||
2a5d6e5157 | |||
c32549fa87 | |||
2689e39d70 | |||
25f2310c25 | |||
0bed5ecf41 | |||
ec2f146095 | |||
75a84baa42 | |||
1bc7ebc92a | |||
d620f577c1 | |||
7af1b40222 | |||
82f1539815 | |||
e38ba012a8 | |||
a0322718c1 | |||
01ca12f80e | |||
3376b4fa7c | |||
308b65e2f6 | |||
fa5b73b5fe | |||
0fd088320d | |||
a109c631cd | |||
cf61a74fa8 | |||
8fa4effb6b | |||
5ca69bbe24 | |||
8816468ba0 | |||
e9f17c585c | |||
373ca377a2 | |||
770420a5b2 | |||
22b1b6bc73 | |||
18fd4bb9d2 | |||
ca333a93e3 | |||
4c404225d2 | |||
9f86a4e0f9 | |||
6273263c4e | |||
0b6b8df1a9 | |||
fe730a19df | |||
636ef87cb1 | |||
d333901576 | |||
d104bcc1fa | |||
dbfbc2c347 | |||
dd620c14d3 | |||
744098abc7 | |||
d41554271d | |||
23bfbf9f4a | |||
f52ed8c791 | |||
604371a2e1 | |||
44cec2d2fb | |||
cbe9ef7303 | |||
002970484d | |||
f063ceb4e5 | |||
1eaefffe04 | |||
1291d21216 | |||
1c198f0133 | |||
23bf656f82 | |||
30fae67f6c | |||
2726955034 | |||
e433bc3319 | |||
71df812170 | |||
abb8540c12 | |||
12e0c23ea9 | |||
b98ecdd0a4 | |||
7314c67357 | |||
6b74e01f0a | |||
6becc08e18 | |||
f66a990103 | |||
c3b9772512 | |||
6bb1cc683c | |||
b5473e05e7 | |||
939ca47e3c | |||
c16e5f1e47 | |||
059f917acc | |||
43b08f22dd | |||
aa7e4a3d3e | |||
18f2b44941 | |||
b2925285a2 | |||
c0a6a3c082 | |||
7c7edcf959 | |||
dee5053345 | |||
58e071e77b | |||
a7e85acd67 | |||
176d184d91 | |||
32543d04a0 | |||
4b43ee86c0 | |||
25959be98f | |||
cb6680304f | |||
40646f16bc | |||
55e7ee2428 | |||
a2930577d3 | |||
e572f50de7 | |||
47b7f5d85a | |||
8ac29e4378 | |||
be81a31302 | |||
2e44a1ef31 | |||
d182cc1418 | |||
d3004019c6 | |||
fca49c6302 | |||
8b085009a9 | |||
2ba6d190f0 | |||
8c5a94a12a | |||
bf9e1f0319 | |||
903baf7f38 | |||
5b585ebba7 | |||
34bae5dc7b | |||
4f97859533 | |||
4c55e65863 | |||
016f0be480 | |||
fbf35d6d77 | |||
30ee1c717e | |||
e3286571b1 | |||
ece39790d2 | |||
eedadb0a3f | |||
00f7cba8fc |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1 +1,3 @@
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.tga filter=lfs diff=lfs merge=lfs -text
|
||||
*.ogg filter=lfs diff=lfs merge=lfs -text
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +0,0 @@
|
||||
Meta
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "Meta"]
|
||||
path = Meta
|
||||
url = https://git.site.quack-lab.dev/dave/wow_Meta
|
5
.luacheckrc
Symbolic link
5
.luacheckrc
Symbolic link
@@ -0,0 +1,5 @@
|
||||
globals = { "CykaPersistentData", "CreateFrame", "GetItemInfo", "aura_env" }
|
||||
unused_args = false
|
||||
max_line_length = 150
|
||||
exclude_files = { "Meta/" }
|
||||
global = false
|
14
.luarc.json
Symbolic link
14
.luarc.json
Symbolic link
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"workspace": {
|
||||
"library": [
|
||||
"./Meta"
|
||||
]
|
||||
},
|
||||
"diagnostics.disable": [
|
||||
"unused-local",
|
||||
"unused-vararg"
|
||||
],
|
||||
"diagnostics.globals": [
|
||||
"aura_env"
|
||||
]
|
||||
}
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"Lua.diagnostics.globals": [
|
||||
"UIParent"
|
||||
]
|
||||
}
|
514
Heimdall.lua
514
Heimdall.lua
@@ -2,15 +2,12 @@ local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
|
||||
-- TODO: Implement counting kills and display on whosniffer
|
||||
-- Take last N seconds of combatlog into account ie. count who does damage to who
|
||||
-- Maybe even make an alert when someone does too much damage to someone else...
|
||||
-- But that would not be trivial as of now, I can't think of a way to do it sensibly
|
||||
local VERSION = "3.12.0"
|
||||
shared.VERSION = VERSION
|
||||
|
||||
local function init()
|
||||
---@class Heimdall_Data
|
||||
---@field config HeimdallConfig
|
||||
---@field stinkies table<string, boolean>
|
||||
if not Heimdall_Data then Heimdall_Data = {} end
|
||||
|
||||
---@class InitTable
|
||||
@@ -22,11 +19,23 @@ local function init()
|
||||
---@field messenger HeimdallMessengerData
|
||||
---@field who HeimdallWhoData
|
||||
---@field stinkyTracker HeimdallStinkyTrackerData
|
||||
---@field networkNodes string[]
|
||||
---@field network HeimdallNetworkData
|
||||
---@field networkMessenger HeimdallNetworkMessengerData
|
||||
---@field stinkyCache HeimdallStinkyCacheData
|
||||
---@field _L fun(key: string, locale: string): string
|
||||
---@field _Locale Localization
|
||||
---@field VERSION string
|
||||
---@field dumpTable fun(table: any, depth?: number): nil
|
||||
---@field utf8len fun(input: string): number
|
||||
---@field padString fun(input: string, targetLength: number, left?: boolean): string
|
||||
---@field GetOrDefault fun(table: table<any, any>, keys: string[], default: any): any
|
||||
---@field Whoer InitTable
|
||||
---@field Split fun(input: string, deliminer: string): string[]
|
||||
---@field IsStinky fun(name: string): boolean
|
||||
---@field Memoize fun(f: function): function
|
||||
---@field GetLocaleForChannel fun(channel: string): string
|
||||
---@field WhoQueryService WhoQueryService
|
||||
---@field Whoer InitTable|{ShouldNotifyForZone: fun(zone: string): boolean}
|
||||
---@field Messenger InitTable
|
||||
---@field Spotter InitTable
|
||||
---@field DeathReporter InitTable
|
||||
@@ -41,6 +50,15 @@ local function init()
|
||||
---@field StinkyTracker InitTable
|
||||
---@field CombatAlerter InitTable
|
||||
---@field Config InitTable
|
||||
---@field Sniffer InitTable
|
||||
---@field MinimapTagger InitTable
|
||||
---@field BonkDetector InitTable
|
||||
---@field Noter InitTable
|
||||
---@field Network InitTable
|
||||
---@field NetworkMessenger InitTable
|
||||
---@field StinkyCache InitTable
|
||||
---@field Configurator InitTable
|
||||
---@field AchievementSniffer InitTable
|
||||
|
||||
--- Config ---
|
||||
---@class HeimdallConfig
|
||||
@@ -58,43 +76,63 @@ local function init()
|
||||
---@field commander HeimdallCommanderConfig
|
||||
---@field stinkyTracker HeimdallStinkyTrackerConfig
|
||||
---@field combatAlerter HeimdallCombatAlerterConfig
|
||||
---@field sniffer HeimdallSnifferConfig
|
||||
---@field bonkDetector HeimdallBonkDetectorConfig
|
||||
---@field noter HeimdallNoterConfig
|
||||
---@field network HeimdallNetworkConfig
|
||||
---@field networkMessenger HeimdallNetworkMessengerConfig
|
||||
---@field configurator HeimdallConfiguratorConfig
|
||||
---@field stinkyCache HeimdallStinkyCacheConfig
|
||||
---@field achievementSniffer HeimdallAchievementSnifferConfig
|
||||
---@field whisperNotify table<string, string>
|
||||
---@field addonPrefix string
|
||||
---@field stinkies table<string, boolean>
|
||||
---@field agents table<string, string>
|
||||
---@field scale number
|
||||
---@field notes table<string, Note[]>
|
||||
---@field channelLocale table<string, string>
|
||||
---@field locale string
|
||||
---@field debug boolean
|
||||
|
||||
---@class HeimdallSpotterConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field everyone boolean
|
||||
---@field hostile boolean
|
||||
---@field alliance boolean
|
||||
---@field stinky boolean
|
||||
---@field notifyChannel string
|
||||
---@field channels string[]
|
||||
---@field zoneOverride string?
|
||||
---@field throttleTime number
|
||||
|
||||
---@class HeimdallWhoConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field ignored table<string, boolean>
|
||||
---@field notifyChannel string
|
||||
---@field channels string[]
|
||||
---@field ttl number
|
||||
---@field doWhisper boolean
|
||||
---@field zoneNotifyFor table<string, boolean>
|
||||
---@field queries string
|
||||
|
||||
---@class HeimdallMessengerConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field interval number
|
||||
|
||||
---@class HeimdallDeathReporterConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field throttle number
|
||||
---@field doWhisper boolean
|
||||
---@field notifyChannel string
|
||||
---@field channels string[]
|
||||
---@field zoneOverride string?
|
||||
---@field duelThrottle number
|
||||
|
||||
---@class HeimdallInviterConfig
|
||||
---@field enabled boolean
|
||||
---@field listeningChannel string
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
---@field keyword string
|
||||
---@field allAssist boolean
|
||||
---@field agentsAssist boolean
|
||||
@@ -102,50 +140,142 @@ local function init()
|
||||
---@field kickOffline boolean
|
||||
---@field cleanupInterval number
|
||||
---@field afkThreshold number
|
||||
---@field listeningChannel table<string, boolean>
|
||||
|
||||
---@class HeimdallDuelerConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field declineOther boolean
|
||||
|
||||
---@class HeimdallBullyConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
|
||||
---@class HeimdallAgentTrackerConfig
|
||||
---@field enabled boolean
|
||||
---@field masterChannel string
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
|
||||
---@class HeimdallEmoterConfig
|
||||
---@field enabled boolean
|
||||
---@field masterChannel string
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
---@field prefix string
|
||||
|
||||
---@class HeimdallEchoerConfig
|
||||
---@field enabled boolean
|
||||
---@field masterChannel string
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
---@field prefix string
|
||||
|
||||
---@class HeimdallMacroerConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field priority string[]
|
||||
|
||||
---@class HeimdallCommanderConfig
|
||||
---@field enabled boolean
|
||||
---@field masterChannel string
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
---@field commander string
|
||||
---@field commands table<string, boolean>
|
||||
|
||||
---@class HeimdallStinkyTrackerConfig
|
||||
---@field enabled boolean
|
||||
---@field masterChannel string
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
|
||||
---@class HeimdallCombatAlerterConfig
|
||||
---@field enabled boolean
|
||||
---@field masterChannel string
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
|
||||
---@class HeimdallSnifferConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
---@field throttle number
|
||||
---@field zoneOverride string?
|
||||
---@field stinky boolean
|
||||
|
||||
---@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
|
||||
|
||||
---@class HeimdallBonkDetectorConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
---@field throttle number
|
||||
|
||||
---@class HeimdallNoterConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field channels string[]
|
||||
---@field lastNotes number
|
||||
|
||||
---@class HeimdallNetworkConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field members string[]
|
||||
---@field updateInterval number
|
||||
|
||||
---@class HeimdallNetworkMessengerConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field interval number
|
||||
|
||||
---@class HeimdallConfiguratorConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
|
||||
---@class HeimdallStinkyCacheConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
---@field commander string
|
||||
---@field ttl number
|
||||
|
||||
---@class HeimdallAchievementSnifferConfig
|
||||
---@field enabled boolean
|
||||
---@field debug boolean
|
||||
-----@field texture string
|
||||
-----@field offsetX number
|
||||
-----@field offsetY number
|
||||
---@field rescan boolean
|
||||
---@field scanInterval number
|
||||
-----@field iconScale number
|
||||
|
||||
--- Data ---
|
||||
---@class HeimdallMessengerData
|
||||
---@field queue table<string, Message>
|
||||
---@field ticker number?
|
||||
---@field ticker Timer?
|
||||
|
||||
---@class HeimdallNetworkMessengerData
|
||||
---@field queue table<string, Message>
|
||||
---@field ticker Timer?
|
||||
|
||||
---@class HeimdallWhoData
|
||||
---@field updateTicker number?
|
||||
@@ -155,6 +285,12 @@ local function init()
|
||||
---@class HeimdallStinkyTrackerData
|
||||
---@field stinkies ReactiveValue
|
||||
|
||||
---@class HeimdallNetworkData
|
||||
---@field ticker number?
|
||||
|
||||
---@class HeimdallStinkyCacheData
|
||||
---@field stinkies table<string, {value: number, timestamp: number}>
|
||||
|
||||
shared.GetOrDefault = function(table, keys, default)
|
||||
local value = default
|
||||
if not table then return value end
|
||||
@@ -169,35 +305,37 @@ local function init()
|
||||
break
|
||||
end
|
||||
|
||||
if i == #keys then
|
||||
value = traverse
|
||||
end
|
||||
if i == #keys then value = traverse end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
shared.messenger = {
|
||||
queue = {}
|
||||
queue = {},
|
||||
}
|
||||
shared.who = {
|
||||
ignored = {},
|
||||
}
|
||||
|
||||
--/run Heimdall_Data.config.who.queries="g-\"БеспредеЛ\"|ally"
|
||||
Heimdall_Data.config = {
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "debug" }, false),
|
||||
spotter = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "enabled" }, true),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "debug" }, false),
|
||||
everyone = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "everyone" }, false),
|
||||
hostile = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "hostile" }, true),
|
||||
alliance = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "alliance" }, true),
|
||||
stinky = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "stinky" }, true),
|
||||
notifyChannel = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "notifyChannel" }, "Agent"),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "channels" }, { "Agent" }),
|
||||
zoneOverride = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "zoneOverride" }, nil),
|
||||
throttleTime = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "throttleTime" }, 10)
|
||||
throttleTime = shared.GetOrDefault(Heimdall_Data, { "config", "spotter", "throttleTime" }, 10),
|
||||
},
|
||||
who = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "who", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "who", "debug" }, false),
|
||||
ignored = shared.GetOrDefault(Heimdall_Data, { "config", "who", "ignored" }, {}),
|
||||
notifyChannel = shared.GetOrDefault(Heimdall_Data, { "config", "who", "notifyChannel" }, "Agent"),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "who", "channels" }, { "Agent" }),
|
||||
ttl = shared.GetOrDefault(Heimdall_Data, { "config", "who", "ttl" }, 20),
|
||||
doWhisper = shared.GetOrDefault(Heimdall_Data, { "config", "who", "doWhisper" }, true),
|
||||
zoneNotifyFor = shared.GetOrDefault(Heimdall_Data, { "config", "who", "zoneNotifyFor" }, {
|
||||
@@ -208,24 +346,26 @@ local function init()
|
||||
["Echo Isles"] = true,
|
||||
["Valley of Trials"] = true,
|
||||
}),
|
||||
queries = shared.GetOrDefault(Heimdall_Data, { "config", "who", "queries" }, ""),
|
||||
},
|
||||
messenger = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "messenger", "enabled" }, true),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "messenger", "debug" }, false),
|
||||
interval = shared.GetOrDefault(Heimdall_Data, { "config", "messenger", "interval" }, 0.2),
|
||||
},
|
||||
deathReporter = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "debug" }, false),
|
||||
throttle = shared.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "throttle" }, 10),
|
||||
doWhisper = shared.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "doWhisper" }, true),
|
||||
notifyChannel = shared.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "notifyChannel" }, "Agent"),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "channels" }, { "Agent" }),
|
||||
zoneOverride = shared.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "zoneOverride" }, nil),
|
||||
duelThrottle = shared.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "duelThrottle" }, 5),
|
||||
},
|
||||
whisperNotify = shared.GetOrDefault(Heimdall_Data, { "config", "whisperNotify" }, {}),
|
||||
stinkies = shared.GetOrDefault(Heimdall_Data, { "config", "stinkies" }, {}),
|
||||
inviter = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "enabled" }, false),
|
||||
listeningChannel = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "listeningChannel" }, "Agent"),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "channels" }, { "Agent" }),
|
||||
keyword = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "keyword" }, "+"),
|
||||
allAssist = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "allAssist" }, false),
|
||||
agentsAssist = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "agentsAssist" }, false),
|
||||
@@ -233,47 +373,199 @@ local function init()
|
||||
kickOffline = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "kickOffline" }, false),
|
||||
cleanupInterval = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "cleanupInterval" }, 10),
|
||||
afkThreshold = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "afkThreshold" }, 300),
|
||||
listeningChannel = shared.GetOrDefault(Heimdall_Data, { "config", "inviter", "listeningChannel" }, {}),
|
||||
},
|
||||
dueler = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "dueler", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "dueler", "debug" }, false),
|
||||
declineOther = shared.GetOrDefault(Heimdall_Data, { "config", "dueler", "declineOther" }, false),
|
||||
},
|
||||
bully = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "bully", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "bully", "debug" }, false),
|
||||
},
|
||||
agentTracker = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "agentTracker", "enabled" }, false),
|
||||
masterChannel = shared.GetOrDefault(Heimdall_Data, { "config", "agentTracker", "masterChannel" }, "Agent"),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "agentTracker", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "agentTracker", "channels" }, { "Agent" }),
|
||||
},
|
||||
emoter = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "emoter", "enabled" }, false),
|
||||
masterChannel = shared.GetOrDefault(Heimdall_Data, { "config", "emoter", "masterChannel" }, "Agent"),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "emoter", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "emoter", "channels" }, { "Agent" }),
|
||||
prefix = shared.GetOrDefault(Heimdall_Data, { "config", "emoter", "prefix" }, ""),
|
||||
},
|
||||
echoer = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "echoer", "enabled" }, false),
|
||||
masterChannel = shared.GetOrDefault(Heimdall_Data, { "config", "echoer", "masterChannel" }, "Agent"),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "echoer", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "echoer", "channels" }, { "Agent" }),
|
||||
prefix = shared.GetOrDefault(Heimdall_Data, { "config", "echoer", "prefix" }, ""),
|
||||
},
|
||||
macroer = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "macroer", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "macroer", "debug" }, false),
|
||||
priority = shared.GetOrDefault(Heimdall_Data, { "config", "macroer", "priority" }, {}),
|
||||
},
|
||||
agents = shared.GetOrDefault(Heimdall_Data, { "config", "agents" }, {}),
|
||||
commander = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "commander", "enabled" }, false),
|
||||
masterChannel = shared.GetOrDefault(Heimdall_Data, { "config", "commander", "masterChannel" }, "Agent"),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "commander", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "commander", "channels" }, { "Agent" }),
|
||||
commander = shared.GetOrDefault(Heimdall_Data, { "config", "commander", "commander" }, "Heimdállr"),
|
||||
commands = shared.GetOrDefault(Heimdall_Data, { "config", "commander", "commands" }, {}),
|
||||
},
|
||||
stinkyTracker = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "stinkyTracker", "enabled" }, false),
|
||||
masterChannel = shared.GetOrDefault(Heimdall_Data, { "config", "stinkyTracker", "masterChannel" }, "Agent"),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "stinkyTracker", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "stinkyTracker", "channels" }, { "Agent" }),
|
||||
},
|
||||
combatAlerter = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "combatAlerter", "enabled" }, false),
|
||||
masterChannel = shared.GetOrDefault(Heimdall_Data, { "config", "combatAlerter", "masterChannel" }, "Agent"),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "combatAlerter", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "combatAlerter", "channels" }, { "Agent" }),
|
||||
},
|
||||
messageDelegator = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "messageDelegator", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "messageDelegator", "debug" }, false),
|
||||
delegates = shared.GetOrDefault(Heimdall_Data, { "config", "messageDelegator", "delegates" }, {}),
|
||||
masterChannel = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "messageDelegator", "masterChannel" },
|
||||
"Agent"
|
||||
),
|
||||
},
|
||||
sniffer = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "sniffer", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "sniffer", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "sniffer", "channels" }, { "Agent" }),
|
||||
throttle = shared.GetOrDefault(Heimdall_Data, { "config", "sniffer", "throttle" }, 10),
|
||||
zoneOverride = shared.GetOrDefault(Heimdall_Data, { "config", "sniffer", "zoneOverride" }, nil),
|
||||
stinky = shared.GetOrDefault(Heimdall_Data, { "config", "sniffer", "stinky" }, true),
|
||||
},
|
||||
minimapTagger = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "channels" }, { "Agent" }),
|
||||
throttle = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "throttle" }, 10),
|
||||
scale = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "scale" }, 3),
|
||||
tagTTL = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "tagTTL" }, 1),
|
||||
tagSound = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "tagSound" }, false),
|
||||
tagSoundFile = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "tagSoundFile" },
|
||||
"MGSSpot.ogg"
|
||||
),
|
||||
tagSoundThrottle = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "tagSoundThrottle" }, 0),
|
||||
tagTextureFile = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "tagTextureFile" },
|
||||
"Aura4.tga"
|
||||
),
|
||||
---
|
||||
alertTTL = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "alertTTL" }, 1),
|
||||
alertSound = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "alertSound" }, false),
|
||||
alertSoundFile = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "alertSoundFile" },
|
||||
"OOF.ogg"
|
||||
),
|
||||
alertSoundThrottle = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "alertSoundThrottle" },
|
||||
0
|
||||
),
|
||||
alertTextureFile = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "alertTextureFile" },
|
||||
"Aura27.tga"
|
||||
),
|
||||
---
|
||||
combatTTL = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "combatTTL" }, 1),
|
||||
combatSound = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "combatSound" }, false),
|
||||
combatSoundFile = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "combatSoundFile" },
|
||||
"StarScream.ogg"
|
||||
),
|
||||
combatSoundThrottle = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "combatSoundThrottle" },
|
||||
2
|
||||
),
|
||||
combatTextureFile = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "combatTextureFile" },
|
||||
"Aura58.tga"
|
||||
),
|
||||
---
|
||||
helpTTL = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "helpTTL" }, 1),
|
||||
helpSound = shared.GetOrDefault(Heimdall_Data, { "config", "minimapTagger", "helpSound" }, false),
|
||||
helpSoundFile = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "helpSoundFile" },
|
||||
"MedicGangsterParadise.ogg"
|
||||
),
|
||||
helpSoundThrottle = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "helpSoundThrottle" },
|
||||
2
|
||||
),
|
||||
helpTextureFile = shared.GetOrDefault(
|
||||
Heimdall_Data,
|
||||
{ "config", "minimapTagger", "helpTextureFile" },
|
||||
"Aura68.tga"
|
||||
),
|
||||
},
|
||||
whisperNotify = shared.GetOrDefault(Heimdall_Data, { "config", "whisperNotify" }, {}),
|
||||
stinkies = shared.GetOrDefault(Heimdall_Data, { "config", "stinkies" }, {}),
|
||||
notes = shared.GetOrDefault(Heimdall_Data, { "config", "notes" }, {}),
|
||||
scale = shared.GetOrDefault(Heimdall_Data, { "config", "scale" }, 1),
|
||||
locale = shared.GetOrDefault(Heimdall_Data, { "config", "locale" }, "en"),
|
||||
bonkDetector = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "bonkDetector", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "bonkDetector", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "bonkDetector", "channels" }, { "Agent" }),
|
||||
throttle = shared.GetOrDefault(Heimdall_Data, { "config", "bonkDetector", "throttle" }, 5),
|
||||
},
|
||||
noter = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "noter", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "noter", "debug" }, false),
|
||||
channels = shared.GetOrDefault(Heimdall_Data, { "config", "noter", "channels" }, { "Agent" }),
|
||||
lastNotes = shared.GetOrDefault(Heimdall_Data, { "config", "noter", "lastNotes" }, 5),
|
||||
},
|
||||
network = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "network", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "network", "debug" }, false),
|
||||
members = shared.GetOrDefault(Heimdall_Data, { "config", "network", "members" }, {}),
|
||||
updateInterval = shared.GetOrDefault(Heimdall_Data, { "config", "network", "updateInterval" }, 10),
|
||||
},
|
||||
networkMessenger = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "networkMessenger", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "networkMessenger", "debug" }, false),
|
||||
interval = shared.GetOrDefault(Heimdall_Data, { "config", "networkMessenger", "interval" }, 0.01),
|
||||
},
|
||||
configurator = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "configurator", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "configurator", "debug" }, false),
|
||||
},
|
||||
stinkyCache = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "stinkyCache", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "stinkyCache", "debug" }, false),
|
||||
commander = shared.GetOrDefault(Heimdall_Data, { "config", "stinkyCache", "commander" }, "Heimdállr"),
|
||||
ttl = shared.GetOrDefault(Heimdall_Data, { "config", "stinkyCache", "ttl" }, 10),
|
||||
},
|
||||
achievementSniffer = {
|
||||
enabled = shared.GetOrDefault(Heimdall_Data, { "config", "achievementSniffer", "enabled" }, false),
|
||||
debug = shared.GetOrDefault(Heimdall_Data, { "config", "achievementSniffer", "debug" }, false),
|
||||
--texture = shared.GetOrDefault(Heimdall_Data, { "config", "achievementSniffer", "texture" }, "Aura53.tga"),
|
||||
--offsetX = shared.GetOrDefault(Heimdall_Data, { "config", "achievementSniffer", "offsetX" }, 0),
|
||||
--offsetY = shared.GetOrDefault(Heimdall_Data, { "config", "achievementSniffer", "offsetY" }, 0),
|
||||
rescan = shared.GetOrDefault(Heimdall_Data, { "config", "achievementSniffer", "rescan" }, false),
|
||||
scanInterval = shared.GetOrDefault(Heimdall_Data, { "config", "achievementSniffer", "scanInterval" }, 1),
|
||||
--iconScale = shared.GetOrDefault(Heimdall_Data, { "config", "achievementSniffer", "iconScale" }, 1),
|
||||
},
|
||||
addonPrefix = shared.GetOrDefault(Heimdall_Data, { "config", "addonPrefix" }, "HEIMDALL"),
|
||||
channelLocale = shared.GetOrDefault(Heimdall_Data, { "config", "channelLocale" }, {}),
|
||||
}
|
||||
|
||||
shared.raceMap = {
|
||||
@@ -297,7 +589,7 @@ local function init()
|
||||
["Void Elf"] = "Alliance",
|
||||
["Lightforged Draenei"] = "Alliance",
|
||||
["Mechagnome"] = "Alliance",
|
||||
["Mag'har Orc"] = "Horde"
|
||||
["Mag'har Orc"] = "Horde",
|
||||
}
|
||||
|
||||
shared.classColors = {
|
||||
@@ -312,15 +604,13 @@ local function init()
|
||||
["Warlock"] = "8788EE",
|
||||
["Monk"] = "00FF98",
|
||||
["Druid"] = "FF7C0A",
|
||||
["Demon Hunter"] = "A330C9"
|
||||
["Demon Hunter"] = "A330C9",
|
||||
}
|
||||
|
||||
---@param input string
|
||||
---@return number
|
||||
shared.utf8len = function(input)
|
||||
if not input then
|
||||
return 0
|
||||
end
|
||||
if not input then return 0 end
|
||||
local len = 0
|
||||
local i = 1
|
||||
local n = #input
|
||||
@@ -358,6 +648,73 @@ local function init()
|
||||
return input
|
||||
end
|
||||
|
||||
---@param input string
|
||||
---@param deliminer string
|
||||
---@return table<number, string>
|
||||
shared.Split = function(input, deliminer)
|
||||
if deliminer == nil then deliminer = "%s" end
|
||||
local t = {}
|
||||
for str in string.gmatch(input, "([^" .. deliminer .. "]+)") do
|
||||
table.insert(t, str)
|
||||
end
|
||||
return t
|
||||
end
|
||||
---@param name string
|
||||
---@return boolean
|
||||
shared.IsStinky = function(name)
|
||||
return Heimdall_Data.config.stinkies[name] ~= nil or shared.StinkyCache[name] ~= nil
|
||||
end
|
||||
|
||||
---@param f function
|
||||
---@return function
|
||||
shared.Memoize = function(f)
|
||||
local mem = {} -- memoizing table
|
||||
setmetatable(mem, { __mode = "kv" }) -- make it weak
|
||||
return function(x) -- new version of ’f’, with memoizing
|
||||
if Heimdall_Data.config.debug then print(string.format("[Heimdall] Memoize %s", tostring(x))) end
|
||||
local r = mem[x]
|
||||
if r == nil then -- no previous result?
|
||||
if Heimdall_Data.config.debug then
|
||||
print(string.format("[Heimdall] Memoize %s is nil, calling original function", tostring(x)))
|
||||
end
|
||||
r = f(x) -- calls original function
|
||||
if Heimdall_Data.config.debug then
|
||||
print(string.format("[Heimdall] Memoized result for %s: %s", tostring(x), tostring(r)))
|
||||
end
|
||||
mem[x] = r -- store result for reuse
|
||||
end
|
||||
if Heimdall_Data.config.debug then
|
||||
print(string.format("[Heimdall] Memoize %s is %s", tostring(x), tostring(r)))
|
||||
end
|
||||
return r
|
||||
end
|
||||
end
|
||||
|
||||
---@param channel string
|
||||
---@return string
|
||||
shared.GetLocaleForChannel = function(channel) return Heimdall_Data.config.channelLocale[channel] or "en" end
|
||||
|
||||
---@param key string
|
||||
---@param locale string
|
||||
---@return string
|
||||
shared._L = function(key, locale)
|
||||
local localeTable = shared._Locale[locale]
|
||||
if not localeTable then
|
||||
if Heimdall_Data.config.debug then
|
||||
print(string.format("[Heimdall] Locale %s not found", tostring(locale)))
|
||||
end
|
||||
return key
|
||||
end
|
||||
local value = localeTable[key]
|
||||
if not value then
|
||||
if Heimdall_Data.config.debug then
|
||||
print(string.format("[Heimdall] Key %s not found in locale %s", tostring(key), tostring(locale)))
|
||||
end
|
||||
return key
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
shared.Messenger.Init()
|
||||
shared.StinkyTracker.Init()
|
||||
shared.AgentTracker.Init()
|
||||
@@ -371,13 +728,86 @@ local function init()
|
||||
shared.Commander.Init()
|
||||
shared.CombatAlerter.Init()
|
||||
shared.Config.Init()
|
||||
shared.MinimapTagger.Init()
|
||||
shared.BonkDetector.Init()
|
||||
shared.Sniffer.Init()
|
||||
shared.Noter.Init()
|
||||
shared.Network.Init()
|
||||
shared.NetworkMessenger.Init()
|
||||
shared.Configurator.Init()
|
||||
shared.StinkyCache.Init()
|
||||
shared.AchievementSniffer.Init()
|
||||
print("Heimdall loaded!")
|
||||
end
|
||||
|
||||
local loadedFrame = CreateFrame("Frame")
|
||||
loadedFrame:RegisterEvent("ADDON_LOADED")
|
||||
loadedFrame:SetScript("OnEvent", function(self, event, addonName)
|
||||
if addonName == addonname then
|
||||
init()
|
||||
end
|
||||
if addonName == addonname then init() end
|
||||
end)
|
||||
|
||||
-- Create the import/export frame
|
||||
local ccpFrame = CreateFrame("Frame", "CCPFrame", UIParent)
|
||||
ccpFrame:SetSize(512 * 1.5, 512 * 1.5)
|
||||
ccpFrame:SetPoint("CENTER")
|
||||
ccpFrame:SetFrameStrata("HIGH")
|
||||
ccpFrame:EnableMouse(true)
|
||||
ccpFrame:SetMovable(true)
|
||||
ccpFrame:SetResizable(false)
|
||||
ccpFrame:SetBackdrop({
|
||||
bgFile = "Interface/Tooltips/UI-Tooltip-Background",
|
||||
edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
|
||||
tile = true,
|
||||
tileSize = 4,
|
||||
edgeSize = 4,
|
||||
insets = {
|
||||
left = 4,
|
||||
right = 4,
|
||||
top = 4,
|
||||
bottom = 4,
|
||||
},
|
||||
})
|
||||
ccpFrame:SetBackdropColor(0, 0, 0, 0.8)
|
||||
ccpFrame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
|
||||
|
||||
ccpFrame:SetMovable(true)
|
||||
ccpFrame:EnableMouse(true)
|
||||
ccpFrame:RegisterForDrag("LeftButton")
|
||||
ccpFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
|
||||
ccpFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
|
||||
ccpFrame:SetScript("OnShow", function(self) self:SetScale(1) end)
|
||||
ccpFrame:Hide()
|
||||
|
||||
-- Create scroll frame
|
||||
local scrollFrame = CreateFrame("ScrollFrame", "CCPFrameScrollFrame", ccpFrame, "UIPanelScrollFrameTemplate")
|
||||
scrollFrame:SetPoint("TOPLEFT", ccpFrame, "TOPLEFT", 10, -10)
|
||||
scrollFrame:SetPoint("BOTTOMRIGHT", ccpFrame, "BOTTOMRIGHT", -30, 10)
|
||||
|
||||
-- Create the text box
|
||||
local ccpFrameTextBox = CreateFrame("EditBox", "CCPFrameTextBox", scrollFrame)
|
||||
ccpFrameTextBox:SetSize(512 * 1.5 - 40, 512 * 1.5 - 20)
|
||||
ccpFrameTextBox:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
|
||||
ccpFrameTextBox:SetFont("Fonts\\FRIZQT__.ttf", 12)
|
||||
ccpFrameTextBox:SetTextColor(1, 1, 1, 1)
|
||||
ccpFrameTextBox:SetTextInsets(10, 10, 10, 10)
|
||||
ccpFrameTextBox:SetMultiLine(true)
|
||||
ccpFrameTextBox:SetAutoFocus(true)
|
||||
ccpFrameTextBox:SetMaxLetters(1000000)
|
||||
ccpFrameTextBox:SetScript("OnEscapePressed", function(self) ccpFrame:Hide() end)
|
||||
|
||||
-- Set the scroll frame's scroll child
|
||||
scrollFrame:SetScrollChild(ccpFrameTextBox)
|
||||
|
||||
CCP = function(window)
|
||||
window = window or 1
|
||||
local charFrame = _G["ChatFrame" .. window]
|
||||
local maxLines = charFrame:GetNumMessages() or 0
|
||||
local chat = {}
|
||||
for i = 1, maxLines do
|
||||
local currentMsg = charFrame:GetMessageInfo(i)
|
||||
chat[#chat + 1] = currentMsg
|
||||
end
|
||||
ccpFrameTextBox:SetText(table.concat(chat, "\n"))
|
||||
ccpFrame:Show()
|
||||
ccpFrameTextBox:SetFocus()
|
||||
end
|
||||
|
15
Heimdall.toc
15
Heimdall.toc
@@ -1,17 +1,18 @@
|
||||
## Interface: 70300
|
||||
## Title: Heimdall
|
||||
## Version: 3.0.0
|
||||
## Version: 3.12.0
|
||||
## Notes: Watches over areas and alerts when hostiles spotted
|
||||
## Author: Cyka
|
||||
## SavedVariables: Heimdall_Data
|
||||
## SavedVariables: Heimdall_Data, Heimdall_Achievements
|
||||
|
||||
#core
|
||||
_L.lua
|
||||
Modules/CLEUParser.lua
|
||||
Modules/ReactiveValue.lua
|
||||
Modules/DumpTable.lua
|
||||
Modules/Spotter.lua
|
||||
Modules/Whoer.lua
|
||||
Modules/Messenger.lua
|
||||
Modules/Network.lua
|
||||
Modules/DeathReporter.lua
|
||||
Modules/Inviter.lua
|
||||
Modules/Dueler.lua
|
||||
@@ -23,5 +24,13 @@ Modules/Macroer.lua
|
||||
Modules/Commander.lua
|
||||
Modules/StinkyTracker.lua
|
||||
Modules/CombatAlerter.lua
|
||||
Modules/MinimapTagger.lua
|
||||
Modules/Config.lua
|
||||
Modules/BonkDetector.lua
|
||||
Modules/Sniffer.lua
|
||||
Modules/Noter.lua
|
||||
Modules/NetworkMessenger.lua
|
||||
Modules/StinkyCache.lua
|
||||
Modules/Configurator.lua
|
||||
Modules/AchievementSniffer.lua
|
||||
Heimdall.lua
|
BIN
Heimdall.zip
(Stored with Git LFS)
BIN
Heimdall.zip
(Stored with Git LFS)
Binary file not shown.
1
Meta
Submodule
1
Meta
Submodule
Submodule Meta added at e0b57e39fc
293
Modules/AchievementSniffer.lua
Normal file
293
Modules/AchievementSniffer.lua
Normal file
@@ -0,0 +1,293 @@
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
local ModuleName = "AchievementSniffer"
|
||||
|
||||
-- local HeimdallRoot = "Interface\\AddOns\\Heimdall\\"
|
||||
-- local TextureRoot = HeimdallRoot .. "Texture\\"
|
||||
|
||||
local Achievements = {
|
||||
15,
|
||||
958,
|
||||
1266,
|
||||
2078,
|
||||
2141,
|
||||
2200,
|
||||
4958,
|
||||
5456,
|
||||
5749,
|
||||
6460,
|
||||
6753,
|
||||
7382,
|
||||
7383,
|
||||
7384,
|
||||
8929,
|
||||
8982,
|
||||
9017,
|
||||
9038,
|
||||
9493,
|
||||
10059,
|
||||
10079,
|
||||
10278,
|
||||
10657,
|
||||
10672,
|
||||
10684,
|
||||
10688,
|
||||
10689,
|
||||
10692,
|
||||
10693,
|
||||
10698,
|
||||
10790,
|
||||
10875,
|
||||
11124,
|
||||
11126,
|
||||
11127,
|
||||
11128,
|
||||
11153,
|
||||
11157,
|
||||
11164,
|
||||
11188,
|
||||
11189,
|
||||
11190,
|
||||
11446,
|
||||
11473,
|
||||
11610,
|
||||
11657,
|
||||
11658,
|
||||
11659,
|
||||
11660,
|
||||
11674,
|
||||
11992,
|
||||
11993,
|
||||
11994,
|
||||
11995,
|
||||
11996,
|
||||
11997,
|
||||
11998,
|
||||
11999,
|
||||
12000,
|
||||
12001,
|
||||
12020,
|
||||
12026,
|
||||
12074,
|
||||
12445,
|
||||
12447,
|
||||
12448,
|
||||
}
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.AchievementSniffer = {}
|
||||
function shared.AchievementSniffer.Init()
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Module initialized", ModuleName))
|
||||
end
|
||||
local guidMap = {}
|
||||
|
||||
---@class AchievementData
|
||||
---@field id number
|
||||
---@field date string
|
||||
---@field completed boolean
|
||||
|
||||
---@class Heimdall_Achievements
|
||||
---@field players table<string, table<number, AchievementData>>
|
||||
---@field alreadySeen table<string, boolean>
|
||||
---@field rescan boolean
|
||||
if not Heimdall_Achievements then Heimdall_Achievements = {} end
|
||||
if not Heimdall_Achievements.players then Heimdall_Achievements.players = {} end
|
||||
if not Heimdall_Achievements.alreadySeen then Heimdall_Achievements.alreadySeen = {} end
|
||||
|
||||
--local framePool = {}
|
||||
--for i = 1, 40 do
|
||||
-- local frame = CreateFrame("Frame", "HeimdallAchievementSnifferNameplate" .. i, UIParent)
|
||||
-- local texture = frame:CreateTexture(nil, "ARTWORK")
|
||||
-- texture:SetAllPoints(frame)
|
||||
-- texture:SetTexture(TextureRoot .. Heimdall_Data.config.achievementSniffer.texture)
|
||||
-- frame.texture = texture
|
||||
-- frame:Hide()
|
||||
-- table.insert(framePool, frame)
|
||||
--end
|
||||
|
||||
---@param name string
|
||||
---@return boolean
|
||||
local function ShouldInspect(name)
|
||||
local should = false
|
||||
if not Heimdall_Achievements.players[name] then
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Player %s does not have prior achievement data", ModuleName, name))
|
||||
end
|
||||
should = true
|
||||
end
|
||||
if Heimdall_Achievements.alreadySeen[name] then
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Player %s has already been seen", ModuleName, name))
|
||||
end
|
||||
-- Save some memory
|
||||
Heimdall_Achievements.players[name] = nil
|
||||
should = false
|
||||
end
|
||||
if Heimdall_Data.config.achievementSniffer.rescan then
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Rescan is enabled", ModuleName))
|
||||
end
|
||||
should = true
|
||||
end
|
||||
return should
|
||||
end
|
||||
|
||||
-- It's not working well AT ALL
|
||||
-- I don't know how to do it better
|
||||
-- It simply just does not work...
|
||||
--local function UpdateFrames()
|
||||
-- for i, frame in ipairs(framePool) do
|
||||
-- local unit = "nameplate" .. i
|
||||
-- if not UnitExists(unit) then
|
||||
-- --if Heimdall_Data.config.achievementSniffer.debug then
|
||||
-- -- print(string.format("[%s] Unit %s does not exist, hiding frame", ModuleName, unit))
|
||||
-- --end
|
||||
-- frame:Hide()
|
||||
-- else
|
||||
-- --local unitFrame = _G[string.format("ElvUI_NamePlate%dHealthBar", i)]
|
||||
-- local unitFrame = _G[string.format("NamePlate%d", i)]
|
||||
-- if unitFrame == nil then
|
||||
-- if Heimdall_Data.config.achievementSniffer.debug then
|
||||
-- print(string.format("[%s] Unit frame for %s not found", ModuleName, unit))
|
||||
-- end
|
||||
-- frame:Hide()
|
||||
-- else
|
||||
-- local unitName = UnitName(unit)
|
||||
-- if Heimdall_Data.config.achievementSniffer.debug then
|
||||
-- print(string.format("[%s] Unit frame found for %s (%s)", ModuleName, unit, unitName))
|
||||
-- end
|
||||
-- frame:Show()
|
||||
-- frame:SetSize(32, 32)
|
||||
-- frame:SetFrameStrata("HIGH")
|
||||
-- frame:SetFrameLevel(100)
|
||||
-- frame:SetScale(Heimdall_Data.config.achievementSniffer.iconScale)
|
||||
-- frame.texture:SetTexture(TextureRoot .. Heimdall_Data.config.achievementSniffer.texture)
|
||||
-- frame:SetPoint("CENTER", unitFrame, "CENTER",
|
||||
-- Heimdall_Data.config.achievementSniffer.offsetX,
|
||||
-- Heimdall_Data.config.achievementSniffer.offsetY)
|
||||
-- frame:SetParent(unitFrame)
|
||||
-- frame:SetAlpha(1)
|
||||
-- local exists = ShouldInspect(unitName)
|
||||
-- if exists then
|
||||
-- frame.texture:SetVertexColor(1, 0, 0, 1)
|
||||
-- else
|
||||
-- frame.texture:SetVertexColor(0, 1, 0, 1)
|
||||
-- end
|
||||
-- if Heimdall_Data.config.achievementSniffer.debug then
|
||||
-- print(string.format("[%s] Frame updated for %s", ModuleName, unitName))
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
--end
|
||||
|
||||
---@param unit string
|
||||
local function TryInspect(unit)
|
||||
local targetPlayer = UnitIsPlayer(unit)
|
||||
if not targetPlayer then return end
|
||||
local targetName = UnitName(unit)
|
||||
local targetGuid = UnitGUID(unit)
|
||||
guidMap[targetGuid] = targetName
|
||||
|
||||
if not ShouldInspect(targetName) then
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Not inspecting player: %s", ModuleName, targetName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local canInspect = CheckInteractDistance(unit, 1)
|
||||
if canInspect then
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Inspecting player: %s", ModuleName, targetName))
|
||||
end
|
||||
SetAchievementComparisonUnit(unit)
|
||||
else
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Cannot inspect player (too far?): %s", ModuleName, targetName))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param name string
|
||||
local function Scan(name)
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Scanning achievements for %s", ModuleName, name))
|
||||
end
|
||||
Heimdall_Achievements.players[name] = {}
|
||||
for i, aid in ipairs(Achievements) do
|
||||
local completed, month, day, year = GetAchievementComparisonInfo(aid)
|
||||
if completed then
|
||||
---@type string
|
||||
local yearstr = "" .. year
|
||||
if year < 100 then yearstr = "20" .. year end
|
||||
|
||||
local date = string.format("%04d-%02d-%02d", yearstr, month, day)
|
||||
|
||||
local data = {
|
||||
id = aid,
|
||||
date = date,
|
||||
completed = completed,
|
||||
}
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Achievement %d completed on %s", ModuleName, aid, date))
|
||||
end
|
||||
Heimdall_Achievements.players[name][aid] = data
|
||||
end
|
||||
end
|
||||
--UpdateFrames()
|
||||
end
|
||||
|
||||
local nameplateFrame = CreateFrame("Frame")
|
||||
nameplateFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED")
|
||||
nameplateFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED")
|
||||
nameplateFrame:SetScript("OnEvent", function(self, event, unit)
|
||||
if not Heimdall_Data.config.achievementSniffer.enabled then return end
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Event triggered: %s for unit: %s", ModuleName, event, unit))
|
||||
end
|
||||
if event == "NAME_PLATE_UNIT_ADDED" then TryInspect(unit) end
|
||||
--UpdateFrames()
|
||||
end)
|
||||
|
||||
local inspectFrame = CreateFrame("Frame")
|
||||
inspectFrame:RegisterEvent("INSPECT_ACHIEVEMENT_READY")
|
||||
inspectFrame:SetScript("OnEvent", function(self, event, guid)
|
||||
if not Heimdall_Data.config.achievementSniffer.enabled then return end
|
||||
local name = guidMap[guid]
|
||||
if not name then
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] No name found for guid: %s", ModuleName, guid))
|
||||
end
|
||||
return
|
||||
end
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Event triggered: %s for player: %s", ModuleName, event, name))
|
||||
end
|
||||
Scan(name)
|
||||
end)
|
||||
|
||||
local function Tick()
|
||||
C_Timer.NewTimer(Heimdall_Data.config.achievementSniffer.scanInterval, Tick)
|
||||
if not Heimdall_Data.config.achievementSniffer.enabled then return end
|
||||
|
||||
if Heimdall_Data.config.achievementSniffer.debug then
|
||||
print(string.format("[%s] Scanning achievements for everyone on screen", ModuleName))
|
||||
end
|
||||
for i = 1, 40 do
|
||||
local unit = "nameplate" .. i
|
||||
if UnitExists(unit) then
|
||||
TryInspect(unit)
|
||||
--else
|
||||
-- if Heimdall_Data.config.achievementSniffer.debug then
|
||||
-- print(string.format("[%s] Unit %s does not exist, nothing to inspect", ModuleName, unit))
|
||||
-- end
|
||||
end
|
||||
end
|
||||
--UpdateFrames()
|
||||
end
|
||||
Tick()
|
||||
|
||||
print("[Heimdall] AchievementSniffer loaded")
|
||||
end
|
@@ -1,39 +1,119 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "AgentTracker"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.AgentTracker = {}
|
||||
function shared.AgentTracker.Init()
|
||||
--/run Heimdall_Data.config.agents["Cyheuraeth"]=date("%Y-%m-%dT%H:%M:%S")
|
||||
---@type table<string, boolean>
|
||||
local channelRosterFrame = CreateFrame("Frame")
|
||||
channelRosterFrame:RegisterEvent("CHANNEL_ROSTER_UPDATE")
|
||||
channelRosterFrame:SetScript("OnEvent", function(self, event, index)
|
||||
if not Heimdall_Data.config.agentTracker.enabled then return end
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(string.format("[%s] Channel roster update received", ModuleName))
|
||||
end
|
||||
if not Heimdall_Data.config.agentTracker.enabled then
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring roster update", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
local name = GetChannelDisplayInfo(index)
|
||||
if name ~= Heimdall_Data.config.agentTracker.masterChannel then return end
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(string.format("[%s] Processing channel update: %s (index: %d)", ModuleName, name or "nil", index))
|
||||
end
|
||||
if name ~= Heimdall_Data.config.agentTracker.masterChannel then
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(string.format("[%s] Ignoring non-master channel: %s", ModuleName, name or "nil"))
|
||||
end
|
||||
return
|
||||
end
|
||||
local count = select(5, GetChannelDisplayInfo(index))
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(string.format("[%s] Processing %d members in channel", ModuleName, count))
|
||||
end
|
||||
|
||||
local newAgents = 0
|
||||
for i = 1, count do
|
||||
local name = GetChannelRosterInfo(index, i)
|
||||
name = GetChannelRosterInfo(index, i)
|
||||
if name then
|
||||
local isNewAgent = not Heimdall_Data.config.agents[name]
|
||||
Heimdall_Data.config.agents[name] = date("%Y-%m-%dT%H:%M:%S")
|
||||
if isNewAgent then newAgents = newAgents + 1 end
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] %s agent: %s",
|
||||
ModuleName,
|
||||
isNewAgent and "Added new" or "Updated existing",
|
||||
name
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
--shared.dumpTable(Heimdall_Data.config.agents)
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(string.format("[%s] Roster update complete - Added %d new agents", ModuleName, newAgents))
|
||||
end
|
||||
end)
|
||||
|
||||
local agentTrackerChannelSniffer = CreateFrame("Frame")
|
||||
agentTrackerChannelSniffer:RegisterEvent("CHAT_MSG_CHANNEL")
|
||||
agentTrackerChannelSniffer:SetScript("OnEvent", function(self, event, msg, sender, ...)
|
||||
if not Heimdall_Data.config.agentTracker.enabled then return end
|
||||
-- if Heimdall_Data.config.agentTracker.debug then
|
||||
-- print(string.format("[%s] Channel message received from: %s", ModuleName, sender))
|
||||
-- end
|
||||
if not Heimdall_Data.config.agentTracker.enabled then
|
||||
-- if Heimdall_Data.config.agentTracker.debug then
|
||||
-- print(string.format("[%s] Module disabled, ignoring channel message", ModuleName))
|
||||
-- end
|
||||
return
|
||||
end
|
||||
|
||||
local channelId = select(6, ...)
|
||||
local channelname = GetChannelName(channelId)
|
||||
if not channelname then return end
|
||||
if channelname ~= Heimdall_Data.config.who.notifyChannel then return end
|
||||
local agentName = sender
|
||||
if not agentName then return end
|
||||
Heimdall_Data.config.agents[agentName] = date("%Y-%m-%dT%H:%M:%S")
|
||||
local _, channelname = GetChannelName(channelId)
|
||||
local ok = false
|
||||
for _, channel in pairs(Heimdall_Data.config.agentTracker.channels) do
|
||||
if channel == channelname then
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not ok then
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(string.format("[%s] Channel name does not match any of the channels", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
|
||||
shared.dumpTable(Heimdall_Data.config.agentTracker)
|
||||
end
|
||||
|
||||
sender = string.match(sender, "^[^-]+")
|
||||
local isNewAgent = not Heimdall_Data.config.agents[sender]
|
||||
Heimdall_Data.config.agents[sender] = date("%Y-%m-%dT%H:%M:%S")
|
||||
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] %s agent from message: %s",
|
||||
ModuleName,
|
||||
isNewAgent and "Added new" or "Updated existing",
|
||||
sender
|
||||
)
|
||||
)
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - AgentTracker loaded")
|
||||
if Heimdall_Data.config.agentTracker.debug then
|
||||
local count = 0
|
||||
for _ in pairs(Heimdall_Data.config.agents) do
|
||||
count = count + 1
|
||||
end
|
||||
print(string.format("[%s] Module initialized - Tracking %d agents", ModuleName, count))
|
||||
end
|
||||
print("[Heimdall] AgentTracker loaded")
|
||||
end
|
||||
|
134
Modules/BonkDetector.lua
Normal file
134
Modules/BonkDetector.lua
Normal file
@@ -0,0 +1,134 @@
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
local ModuleName = "BonkDetector"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.BonkDetector = {}
|
||||
function shared.BonkDetector.Init()
|
||||
---@type table<string, number>
|
||||
local lastReportTime = {}
|
||||
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
|
||||
frame:SetScript("OnEvent", function(self, event, ...)
|
||||
-- if Heimdall_Data.config.bonkDetector.debug then
|
||||
-- print(string.format("[%s] Combat log event received", ModuleName))
|
||||
-- end
|
||||
if not Heimdall_Data.config.bonkDetector.enabled then
|
||||
-- if Heimdall_Data.config.bonkDetector.debug then
|
||||
-- print(string.format("[%s] Module disabled, ignoring combat event", ModuleName))
|
||||
-- end
|
||||
return
|
||||
end
|
||||
|
||||
local subevent = select(2, ...)
|
||||
if not subevent:find("_DAMAGE") then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Not a damage event, ignoring: %s", ModuleName, subevent))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
---@type string|nil, string, string, string, string
|
||||
local err, source, sourceGUID, destination, destinationGUID
|
||||
|
||||
source, err = CLEUParser.GetSourceName(...)
|
||||
if err then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Error getting source name: %s", ModuleName, err))
|
||||
end
|
||||
return
|
||||
end
|
||||
sourceGUID, err = CLEUParser.GetSourceGUID(...)
|
||||
if err then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Error getting source GUID: %s", ModuleName, err))
|
||||
end
|
||||
return
|
||||
end
|
||||
if not string.find(sourceGUID, "Player") then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Source %s is not a player, nothing to do", ModuleName, source))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
destination, err = CLEUParser.GetDestName(...)
|
||||
if err then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Error getting destination name: %s", ModuleName, err))
|
||||
end
|
||||
return
|
||||
end
|
||||
destinationGUID, err = CLEUParser.GetDestGUID(...)
|
||||
if err then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Error getting destination GUID: %s", ModuleName, err))
|
||||
end
|
||||
return
|
||||
end
|
||||
if not string.find(destinationGUID, "Player") then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Destination %s is not a player, nothing to do", ModuleName, destination))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if source == destination then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Source and destination are the same, ignoring event", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local currentTime = GetTime()
|
||||
local throttle = Heimdall_Data.config.bonkDetector.throttle
|
||||
|
||||
if lastReportTime[source] and (currentTime - lastReportTime[source]) < throttle then
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
local timeLeft = throttle - (currentTime - lastReportTime[source])
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Damage report throttled for %s (%.1f seconds remaining)",
|
||||
ModuleName,
|
||||
source,
|
||||
timeLeft
|
||||
)
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
lastReportTime[source] = currentTime
|
||||
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Processing damage event - Source: %s, Target: %s, Type: %s",
|
||||
ModuleName,
|
||||
source,
|
||||
destination,
|
||||
subevent
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
for _, channel in pairs(Heimdall_Data.config.bonkDetector.channels) do
|
||||
local locale = shared.GetLocaleForChannel(channel)
|
||||
local msg = string.format(shared._L("bonkDetected", locale), source, destination, subevent)
|
||||
---@type Message
|
||||
local message = {
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = msg,
|
||||
}
|
||||
if Heimdall_Data.config.bonkDetector.debug then
|
||||
print(string.format("[%s] Queuing bonk detector message", ModuleName))
|
||||
shared.dumpTable(message)
|
||||
end
|
||||
table.insert(shared.messenger.queue, message)
|
||||
end
|
||||
end)
|
||||
|
||||
print("[Heimdall] BonkDetector loaded")
|
||||
end
|
@@ -1,9 +1,10 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Bully"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Bully = {}
|
||||
function shared.Bully.Init()
|
||||
print("Heimdall - Bully loaded")
|
||||
if Heimdall_Data.config.bully.debug then print(string.format("[%s] Module initialized", ModuleName)) end
|
||||
print("[Heimdall] Bully loaded")
|
||||
end
|
||||
|
@@ -12,12 +12,12 @@ local function Init()
|
||||
["destGUID"] = 8,
|
||||
["destName"] = 9,
|
||||
["destFlags"] = 10,
|
||||
["destRaidFlags"] = 11
|
||||
["destRaidFlags"] = 11,
|
||||
},
|
||||
["GENERIC_SPELL"] = {
|
||||
["spellId"] = 12,
|
||||
["spellName"] = 13,
|
||||
["spellSchool"] = 14
|
||||
["spellSchool"] = 14,
|
||||
},
|
||||
["GENERIC_DAMAGE"] = {
|
||||
["amount"] = 15,
|
||||
@@ -29,19 +29,19 @@ local function Init()
|
||||
["critical"] = 21,
|
||||
["glancing"] = 22,
|
||||
["crushing"] = 23,
|
||||
["isOffHand"] = 24
|
||||
["isOffHand"] = 24,
|
||||
},
|
||||
["GENERIC_MISSED"] = {
|
||||
["missType"] = 15,
|
||||
["isOffHand"] = 16,
|
||||
["amountMissed"] = 17,
|
||||
["critical"] = 18
|
||||
["critical"] = 18,
|
||||
},
|
||||
["GENERIC_HEAL"] = {
|
||||
["amount"] = 15,
|
||||
["overhealing"] = 16,
|
||||
["absorbed"] = 17,
|
||||
["critical"] = 18
|
||||
["critical"] = 18,
|
||||
},
|
||||
["GENERIC_HEAL_ABSORBED"] = {
|
||||
["extraGUID"] = 15,
|
||||
@@ -52,44 +52,44 @@ local function Init()
|
||||
["extraSpellName"] = 20,
|
||||
["extraSchool"] = 21,
|
||||
["absorbedAmount"] = 22,
|
||||
["totalAmount"] = 23
|
||||
["totalAmount"] = 23,
|
||||
},
|
||||
["GENERIC_ENERGIZE"] = {
|
||||
["amount"] = 15,
|
||||
["overEnergize"] = 16,
|
||||
["powerType"] = 17
|
||||
["powerType"] = 17,
|
||||
},
|
||||
["GENERIC_DRAIN"] = {
|
||||
["amount"] = 15,
|
||||
["powerType"] = 16,
|
||||
["extraAmount"] = 17
|
||||
["extraAmount"] = 17,
|
||||
},
|
||||
["GENERIC_LEECH"] = {
|
||||
["amount"] = 15,
|
||||
["powerType"] = 16,
|
||||
["extraAmount"] = 17
|
||||
["extraAmount"] = 17,
|
||||
},
|
||||
["GENERIC_INTERRUPT"] = {
|
||||
["extraSpellId"] = 15,
|
||||
["extraSpellName"] = 16,
|
||||
["extraSchool"] = 17
|
||||
["extraSchool"] = 17,
|
||||
},
|
||||
["GENERIC_DISPEL"] = {
|
||||
["extraSpellId"] = 15,
|
||||
["extraSpellName"] = 16,
|
||||
["extraSchool"] = 17,
|
||||
["auraType"] = 18
|
||||
["auraType"] = 18,
|
||||
},
|
||||
["GENERIC_DISPEL_FAILED"] = {
|
||||
["extraSpellId"] = 15,
|
||||
["extraSpellName"] = 16,
|
||||
["extraSchool"] = 17
|
||||
["extraSchool"] = 17,
|
||||
},
|
||||
["GENERIC_STOLEN"] = {
|
||||
["extraSpellId"] = 15,
|
||||
["extraSpellName"] = 16,
|
||||
["extraSchool"] = 17,
|
||||
["auraType"] = 18
|
||||
["auraType"] = 18,
|
||||
},
|
||||
["GENERIC_EXTRA_ATTACKS"] = { ["amount"] = 15 },
|
||||
["GENERIC_AURA_APPLIED"] = { ["auraType"] = 15, ["amount"] = 16 },
|
||||
@@ -102,38 +102,32 @@ local function Init()
|
||||
["extraSpellId"] = 15,
|
||||
["extraSpellName"] = 16,
|
||||
["extraSchool"] = 17,
|
||||
["auraType"] = 18
|
||||
["auraType"] = 18,
|
||||
},
|
||||
["GENERIC_CAST_START"] = {},
|
||||
["GENERIC_CAST_SUCCESS"] = {},
|
||||
["GENERIC_CAST_FAILED"] = {}
|
||||
["GENERIC_CAST_FAILED"] = {},
|
||||
}
|
||||
|
||||
CLEUEventInfo["SWING_DAMAGE"] = CLEUEventInfo["GENERIC_DAMAGE"]
|
||||
CLEUEventInfo["SWING_MISSED"] = CLEUEventInfo["GENERIC_MISSED"]
|
||||
CLEUEventInfo["SWING_HEAL"] = CLEUEventInfo["GENERIC_HEAL"]
|
||||
CLEUEventInfo["SWING_HEAL_ABSORBED"] =
|
||||
CLEUEventInfo["GENERIC_HEAL_ABSORBED"]
|
||||
CLEUEventInfo["SWING_HEAL_ABSORBED"] = CLEUEventInfo["GENERIC_HEAL_ABSORBED"]
|
||||
CLEUEventInfo["SWING_ENERGIZE"] = CLEUEventInfo["GENERIC_ENERGIZE"]
|
||||
CLEUEventInfo["SWING_DRAIN"] = CLEUEventInfo["GENERIC_DRAIN"]
|
||||
CLEUEventInfo["SWING_LEECH"] = CLEUEventInfo["GENERIC_LEECH"]
|
||||
CLEUEventInfo["SWING_INTERRUPT"] = CLEUEventInfo["GENERIC_INTERRUPT"]
|
||||
CLEUEventInfo["SWING_DISPEL"] = CLEUEventInfo["GENERIC_DISPEL"]
|
||||
CLEUEventInfo["SWING_DISPEL_FAILED"] =
|
||||
CLEUEventInfo["GENERIC_DISPEL_FAILED"]
|
||||
CLEUEventInfo["SWING_DISPEL_FAILED"] = CLEUEventInfo["GENERIC_DISPEL_FAILED"]
|
||||
CLEUEventInfo["SWING_STOLEN"] = CLEUEventInfo["GENERIC_STOLEN"]
|
||||
CLEUEventInfo["SWING_EXTRA_ATTACKS"] =
|
||||
CLEUEventInfo["GENERIC_EXTRA_ATTACKS"]
|
||||
CLEUEventInfo["SWING_EXTRA_ATTACKS"] = CLEUEventInfo["GENERIC_EXTRA_ATTACKS"]
|
||||
CLEUEventInfo["SWING_AURA_APPLIED"] = CLEUEventInfo["GENERIC_AURA_APPLIED"]
|
||||
CLEUEventInfo["SWING_AURA_REMOVED"] = CLEUEventInfo["GENERIC_AURA_REMOVED"]
|
||||
CLEUEventInfo["SWING_AURA_APPLIED_DOSE"] =
|
||||
CLEUEventInfo["GENERIC_AURA_APPLIED_DOSE"]
|
||||
CLEUEventInfo["SWING_AURA_REMOVED_DOSE"] =
|
||||
CLEUEventInfo["GENERIC_AURA_REMOVED_DOSE"]
|
||||
CLEUEventInfo["SWING_AURA_APPLIED_DOSE"] = CLEUEventInfo["GENERIC_AURA_APPLIED_DOSE"]
|
||||
CLEUEventInfo["SWING_AURA_REMOVED_DOSE"] = CLEUEventInfo["GENERIC_AURA_REMOVED_DOSE"]
|
||||
CLEUEventInfo["SWING_AURA_REFRESH"] = CLEUEventInfo["GENERIC_AURA_REFRESH"]
|
||||
CLEUEventInfo["SWING_AURA_BROKEN"] = CLEUEventInfo["GENERIC_AURA_BROKEN"]
|
||||
CLEUEventInfo["SWING_AURA_BROKEN_SPELL"] =
|
||||
CLEUEventInfo["GENERIC_AURA_BROKEN_SPELL"]
|
||||
CLEUEventInfo["SWING_AURA_BROKEN_SPELL"] = CLEUEventInfo["GENERIC_AURA_BROKEN_SPELL"]
|
||||
CLEUEventInfo["SWING_CAST_START"] = CLEUEventInfo["GENERIC_CAST_START"]
|
||||
CLEUEventInfo["SWING_CAST_SUCCESS"] = CLEUEventInfo["GENERIC_CAST_SUCCESS"]
|
||||
CLEUEventInfo["SWING_CAST_FAILED"] = CLEUEventInfo["GENERIC_CAST_FAILED"]
|
||||
@@ -141,28 +135,22 @@ local function Init()
|
||||
CLEUEventInfo["RANGE_DAMAGE"] = CLEUEventInfo["GENERIC_DAMAGE"]
|
||||
CLEUEventInfo["RANGE_MISSED"] = CLEUEventInfo["GENERIC_MISSED"]
|
||||
CLEUEventInfo["RANGE_HEAL"] = CLEUEventInfo["GENERIC_HEAL"]
|
||||
CLEUEventInfo["RANGE_HEAL_ABSORBED"] =
|
||||
CLEUEventInfo["GENERIC_HEAL_ABSORBED"]
|
||||
CLEUEventInfo["RANGE_HEAL_ABSORBED"] = CLEUEventInfo["GENERIC_HEAL_ABSORBED"]
|
||||
CLEUEventInfo["RANGE_ENERGIZE"] = CLEUEventInfo["GENERIC_ENERGIZE"]
|
||||
CLEUEventInfo["RANGE_DRAIN"] = CLEUEventInfo["GENERIC_DRAIN"]
|
||||
CLEUEventInfo["RANGE_LEECH"] = CLEUEventInfo["GENERIC_LEECH"]
|
||||
CLEUEventInfo["RANGE_INTERRUPT"] = CLEUEventInfo["GENERIC_INTERRUPT"]
|
||||
CLEUEventInfo["RANGE_DISPEL"] = CLEUEventInfo["GENERIC_DISPEL"]
|
||||
CLEUEventInfo["RANGE_DISPEL_FAILED"] =
|
||||
CLEUEventInfo["GENERIC_DISPEL_FAILED"]
|
||||
CLEUEventInfo["RANGE_DISPEL_FAILED"] = CLEUEventInfo["GENERIC_DISPEL_FAILED"]
|
||||
CLEUEventInfo["RANGE_STOLEN"] = CLEUEventInfo["GENERIC_STOLEN"]
|
||||
CLEUEventInfo["RANGE_EXTRA_ATTACKS"] =
|
||||
CLEUEventInfo["GENERIC_EXTRA_ATTACKS"]
|
||||
CLEUEventInfo["RANGE_EXTRA_ATTACKS"] = CLEUEventInfo["GENERIC_EXTRA_ATTACKS"]
|
||||
CLEUEventInfo["RANGE_AURA_APPLIED"] = CLEUEventInfo["GENERIC_AURA_APPLIED"]
|
||||
CLEUEventInfo["RANGE_AURA_REMOVED"] = CLEUEventInfo["GENERIC_AURA_REMOVED"]
|
||||
CLEUEventInfo["RANGE_AURA_APPLIED_DOSE"] =
|
||||
CLEUEventInfo["GENERIC_AURA_APPLIED_DOSE"]
|
||||
CLEUEventInfo["RANGE_AURA_REMOVED_DOSE"] =
|
||||
CLEUEventInfo["GENERIC_AURA_REMOVED_DOSE"]
|
||||
CLEUEventInfo["RANGE_AURA_APPLIED_DOSE"] = CLEUEventInfo["GENERIC_AURA_APPLIED_DOSE"]
|
||||
CLEUEventInfo["RANGE_AURA_REMOVED_DOSE"] = CLEUEventInfo["GENERIC_AURA_REMOVED_DOSE"]
|
||||
CLEUEventInfo["RANGE_AURA_REFRESH"] = CLEUEventInfo["GENERIC_AURA_REFRESH"]
|
||||
CLEUEventInfo["RANGE_AURA_BROKEN"] = CLEUEventInfo["GENERIC_AURA_BROKEN"]
|
||||
CLEUEventInfo["RANGE_AURA_BROKEN_SPELL"] =
|
||||
CLEUEventInfo["GENERIC_AURA_BROKEN_SPELL"]
|
||||
CLEUEventInfo["RANGE_AURA_BROKEN_SPELL"] = CLEUEventInfo["GENERIC_AURA_BROKEN_SPELL"]
|
||||
CLEUEventInfo["RANGE_CAST_START"] = CLEUEventInfo["GENERIC_CAST_START"]
|
||||
CLEUEventInfo["RANGE_CAST_SUCCESS"] = CLEUEventInfo["GENERIC_CAST_SUCCESS"]
|
||||
CLEUEventInfo["RANGE_CAST_FAILED"] = CLEUEventInfo["GENERIC_CAST_FAILED"]
|
||||
@@ -170,28 +158,22 @@ local function Init()
|
||||
CLEUEventInfo["SPELL_DAMAGE"] = CLEUEventInfo["GENERIC_DAMAGE"]
|
||||
CLEUEventInfo["SPELL_MISSED"] = CLEUEventInfo["GENERIC_MISSED"]
|
||||
CLEUEventInfo["SPELL_HEAL"] = CLEUEventInfo["GENERIC_HEAL"]
|
||||
CLEUEventInfo["SPELL_HEAL_ABSORBED"] =
|
||||
CLEUEventInfo["GENERIC_HEAL_ABSORBED"]
|
||||
CLEUEventInfo["SPELL_HEAL_ABSORBED"] = CLEUEventInfo["GENERIC_HEAL_ABSORBED"]
|
||||
CLEUEventInfo["SPELL_ENERGIZE"] = CLEUEventInfo["GENERIC_ENERGIZE"]
|
||||
CLEUEventInfo["SPELL_DRAIN"] = CLEUEventInfo["GENERIC_DRAIN"]
|
||||
CLEUEventInfo["SPELL_LEECH"] = CLEUEventInfo["GENERIC_LEECH"]
|
||||
CLEUEventInfo["SPELL_INTERRUPT"] = CLEUEventInfo["GENERIC_INTERRUPT"]
|
||||
CLEUEventInfo["SPELL_DISPEL"] = CLEUEventInfo["GENERIC_DISPEL"]
|
||||
CLEUEventInfo["SPELL_DISPEL_FAILED"] =
|
||||
CLEUEventInfo["GENERIC_DISPEL_FAILED"]
|
||||
CLEUEventInfo["SPELL_DISPEL_FAILED"] = CLEUEventInfo["GENERIC_DISPEL_FAILED"]
|
||||
CLEUEventInfo["SPELL_STOLEN"] = CLEUEventInfo["GENERIC_STOLEN"]
|
||||
CLEUEventInfo["SPELL_EXTRA_ATTACKS"] =
|
||||
CLEUEventInfo["GENERIC_EXTRA_ATTACKS"]
|
||||
CLEUEventInfo["SPELL_EXTRA_ATTACKS"] = CLEUEventInfo["GENERIC_EXTRA_ATTACKS"]
|
||||
CLEUEventInfo["SPELL_AURA_APPLIED"] = CLEUEventInfo["GENERIC_AURA_APPLIED"]
|
||||
CLEUEventInfo["SPELL_AURA_REMOVED"] = CLEUEventInfo["GENERIC_AURA_REMOVED"]
|
||||
CLEUEventInfo["SPELL_AURA_APPLIED_DOSE"] =
|
||||
CLEUEventInfo["GENERIC_AURA_APPLIED_DOSE"]
|
||||
CLEUEventInfo["SPELL_AURA_REMOVED_DOSE"] =
|
||||
CLEUEventInfo["GENERIC_AURA_REMOVED_DOSE"]
|
||||
CLEUEventInfo["SPELL_AURA_APPLIED_DOSE"] = CLEUEventInfo["GENERIC_AURA_APPLIED_DOSE"]
|
||||
CLEUEventInfo["SPELL_AURA_REMOVED_DOSE"] = CLEUEventInfo["GENERIC_AURA_REMOVED_DOSE"]
|
||||
CLEUEventInfo["SPELL_AURA_REFRESH"] = CLEUEventInfo["GENERIC_AURA_REFRESH"]
|
||||
CLEUEventInfo["SPELL_AURA_BROKEN"] = CLEUEventInfo["GENERIC_AURA_BROKEN"]
|
||||
CLEUEventInfo["SPELL_AURA_BROKEN_SPELL"] =
|
||||
CLEUEventInfo["GENERIC_AURA_BROKEN_SPELL"]
|
||||
CLEUEventInfo["SPELL_AURA_BROKEN_SPELL"] = CLEUEventInfo["GENERIC_AURA_BROKEN_SPELL"]
|
||||
CLEUEventInfo["SPELL_CAST_START"] = CLEUEventInfo["GENERIC_CAST_START"]
|
||||
CLEUEventInfo["SPELL_CAST_SUCCESS"] = CLEUEventInfo["GENERIC_CAST_SUCCESS"]
|
||||
CLEUEventInfo["SPELL_CAST_FAILED"] = CLEUEventInfo["GENERIC_CAST_FAILED"]
|
||||
@@ -199,39 +181,25 @@ local function Init()
|
||||
CLEUEventInfo["SPELL_PERIODIC_DAMAGE"] = CLEUEventInfo["GENERIC_DAMAGE"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_MISSED"] = CLEUEventInfo["GENERIC_MISSED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_HEAL"] = CLEUEventInfo["GENERIC_HEAL"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_HEAL_ABSORBED"] =
|
||||
CLEUEventInfo["GENERIC_HEAL_ABSORBED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_HEAL_ABSORBED"] = CLEUEventInfo["GENERIC_HEAL_ABSORBED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_ENERGIZE"] = CLEUEventInfo["GENERIC_ENERGIZE"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_DRAIN"] = CLEUEventInfo["GENERIC_DRAIN"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_LEECH"] = CLEUEventInfo["GENERIC_LEECH"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_INTERRUPT"] =
|
||||
CLEUEventInfo["GENERIC_INTERRUPT"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_INTERRUPT"] = CLEUEventInfo["GENERIC_INTERRUPT"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_DISPEL"] = CLEUEventInfo["GENERIC_DISPEL"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_DISPEL_FAILED"] =
|
||||
CLEUEventInfo["GENERIC_DISPEL_FAILED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_DISPEL_FAILED"] = CLEUEventInfo["GENERIC_DISPEL_FAILED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_STOLEN"] = CLEUEventInfo["GENERIC_STOLEN"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_EXTRA_ATTACKS"] =
|
||||
CLEUEventInfo["GENERIC_EXTRA_ATTACKS"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_APPLIED"] =
|
||||
CLEUEventInfo["GENERIC_AURA_APPLIED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_REMOVED"] =
|
||||
CLEUEventInfo["GENERIC_AURA_REMOVED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_APPLIED_DOSE"] =
|
||||
CLEUEventInfo["GENERIC_AURA_APPLIED_DOSE"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_REMOVED_DOSE"] =
|
||||
CLEUEventInfo["GENERIC_AURA_REMOVED_DOSE"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_REFRESH"] =
|
||||
CLEUEventInfo["GENERIC_AURA_REFRESH"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_BROKEN"] =
|
||||
CLEUEventInfo["GENERIC_AURA_BROKEN"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_BROKEN_SPELL"] =
|
||||
CLEUEventInfo["GENERIC_AURA_BROKEN_SPELL"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_CAST_START"] =
|
||||
CLEUEventInfo["GENERIC_CAST_START"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_CAST_SUCCESS"] =
|
||||
CLEUEventInfo["GENERIC_CAST_SUCCESS"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_CAST_FAILED"] =
|
||||
CLEUEventInfo["GENERIC_CAST_FAILED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_EXTRA_ATTACKS"] = CLEUEventInfo["GENERIC_EXTRA_ATTACKS"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_APPLIED"] = CLEUEventInfo["GENERIC_AURA_APPLIED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_REMOVED"] = CLEUEventInfo["GENERIC_AURA_REMOVED"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_APPLIED_DOSE"] = CLEUEventInfo["GENERIC_AURA_APPLIED_DOSE"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_REMOVED_DOSE"] = CLEUEventInfo["GENERIC_AURA_REMOVED_DOSE"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_REFRESH"] = CLEUEventInfo["GENERIC_AURA_REFRESH"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_BROKEN"] = CLEUEventInfo["GENERIC_AURA_BROKEN"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_AURA_BROKEN_SPELL"] = CLEUEventInfo["GENERIC_AURA_BROKEN_SPELL"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_CAST_START"] = CLEUEventInfo["GENERIC_CAST_START"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_CAST_SUCCESS"] = CLEUEventInfo["GENERIC_CAST_SUCCESS"]
|
||||
CLEUEventInfo["SPELL_PERIODIC_CAST_FAILED"] = CLEUEventInfo["GENERIC_CAST_FAILED"]
|
||||
|
||||
---@class CLEUParser
|
||||
CLEUParser = {
|
||||
@@ -239,132 +207,88 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetTimestamp = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["timestamp"], ...)
|
||||
if val == nil then
|
||||
return 0, "Timestamp is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "Timestamp is not a number"
|
||||
end
|
||||
if val == nil then return 0, "Timestamp is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "Timestamp is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return string, nil|string
|
||||
GetSubevent = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["subevent"], ...)
|
||||
if val == nil then
|
||||
return "", "Subevent is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "Subevent is not a string"
|
||||
end
|
||||
if val == nil then return "", "Subevent is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "Subevent is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return boolean, nil|string
|
||||
GetHideCaster = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["hideCaster"], ...)
|
||||
if val == nil then
|
||||
return false, "HideCaster is nil or missing"
|
||||
end
|
||||
if type(val) ~= "boolean" then
|
||||
return false, "HideCaster is not a boolean"
|
||||
end
|
||||
if val == nil then return false, "HideCaster is nil or missing" end
|
||||
if type(val) ~= "boolean" then return false, "HideCaster is not a boolean" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return string, nil|string
|
||||
GetSourceGUID = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["sourceGUID"], ...)
|
||||
if val == nil then
|
||||
return "", "SourceGUID is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "SourceGUID is not a string"
|
||||
end
|
||||
if val == nil then return "", "SourceGUID is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "SourceGUID is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return string, nil|string
|
||||
GetSourceName = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["sourceName"], ...)
|
||||
if val == nil then
|
||||
return "", "SourceName is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "SourceName is not a string"
|
||||
end
|
||||
if val == nil then return "", "SourceName is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "SourceName is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return number, nil|string
|
||||
GetSourceFlags = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["sourceFlags"], ...)
|
||||
if val == nil then
|
||||
return 0, "SourceFlags is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "SourceFlags is not a number"
|
||||
end
|
||||
if val == nil then return 0, "SourceFlags is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "SourceFlags is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return number, nil|string
|
||||
GetSourceRaidFlags = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["sourceRaidFlags"], ...)
|
||||
if val == nil then
|
||||
return 0, "SourceRaidFlags is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "SourceRaidFlags is not a number"
|
||||
end
|
||||
if val == nil then return 0, "SourceRaidFlags is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "SourceRaidFlags is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return string, nil|string
|
||||
GetDestGUID = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["destGUID"], ...)
|
||||
if val == nil then
|
||||
return "", "DestGUID is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "DestGUID is not a string"
|
||||
end
|
||||
if val == nil then return "", "DestGUID is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "DestGUID is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return string, nil|string
|
||||
GetDestName = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["destName"], ...)
|
||||
if val == nil then
|
||||
return "", "DestName is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "DestName is not a string"
|
||||
end
|
||||
if val == nil then return "", "DestName is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "DestName is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return number, nil|string
|
||||
GetDestFlags = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["destFlags"], ...)
|
||||
if val == nil then
|
||||
return 0, "DestFlags is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "DestFlags is not a number"
|
||||
end
|
||||
if val == nil then return 0, "DestFlags is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "DestFlags is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
---@param ... any
|
||||
---@return number, nil|string
|
||||
GetDestRaidFlags = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC"]["destRaidFlags"], ...)
|
||||
if val == nil then
|
||||
return 0, "DestRaidFlags is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "DestRaidFlags is not a number"
|
||||
end
|
||||
if val == nil then return 0, "DestRaidFlags is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "DestRaidFlags is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -380,9 +304,7 @@ local function Init()
|
||||
GetSpellId = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC_SPELL"]["spellId"], ...)
|
||||
if val == nil then return 0, "SpellId is nil or missing" end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "SpellId is not a number"
|
||||
end
|
||||
if type(val) ~= "number" then return 0, "SpellId is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -396,12 +318,8 @@ local function Init()
|
||||
---@return string, nil|string
|
||||
GetSpellName = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC_SPELL"]["spellName"], ...)
|
||||
if val == nil then
|
||||
return "", "SpellName is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "SpellName is not a string"
|
||||
end
|
||||
if val == nil then return "", "SpellName is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "SpellName is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -414,14 +332,9 @@ local function Init()
|
||||
---@param ... any
|
||||
---@return number, nil|string
|
||||
GetSpellSchool = function(...)
|
||||
local val = select(CLEUEventInfo["GENERIC_SPELL"]["spellSchool"],
|
||||
...)
|
||||
if val == nil then
|
||||
return 0, "SpellSchool is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "SpellSchool is not a number"
|
||||
end
|
||||
local val = select(CLEUEventInfo["GENERIC_SPELL"]["spellSchool"], ...)
|
||||
if val == nil then return 0, "SpellSchool is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "SpellSchool is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -451,15 +364,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetAmount = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["amount"], ...)
|
||||
if val == nil then return 0, "Amount is nil or missing" end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "Amount is not a number"
|
||||
end
|
||||
if type(val) ~= "number" then return 0, "Amount is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -479,21 +387,12 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetOverkill = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if not CLEUEventInfo[subevent] then
|
||||
return 0, "Subevent is not a valid event"
|
||||
end
|
||||
if not CLEUEventInfo[subevent]["overkill"] then
|
||||
return 0, "Overkill is nil or missing"
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
if not CLEUEventInfo[subevent] then return 0, "Subevent is not a valid event" end
|
||||
if not CLEUEventInfo[subevent]["overkill"] then return 0, "Overkill is nil or missing" end
|
||||
local val = select(CLEUEventInfo[subevent]["overkill"], ...)
|
||||
if val == nil then return 0, "Overkill is nil or missing" end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "Overkill is not a number"
|
||||
end
|
||||
if type(val) ~= "number" then return 0, "Overkill is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -513,15 +412,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetSchool = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["school"], ...)
|
||||
if val == nil then return 0, "School is nil or missing" end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "School is not a number"
|
||||
end
|
||||
if type(val) ~= "number" then return 0, "School is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -543,17 +437,10 @@ local function Init()
|
||||
---@return boolean, nil|string
|
||||
GetResisted = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return false,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return false, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["resisted"], ...)
|
||||
if val == nil then
|
||||
return false, "Resisted is nil or missing"
|
||||
end
|
||||
if type(val) ~= "boolean" then
|
||||
return false, "Resisted is not a boolean"
|
||||
end
|
||||
if val == nil then return false, "Resisted is nil or missing" end
|
||||
if type(val) ~= "boolean" then return false, "Resisted is not a boolean" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -575,17 +462,10 @@ local function Init()
|
||||
---@return boolean, nil|string
|
||||
GetBlocked = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return false,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return false, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["blocked"], ...)
|
||||
if val == nil then
|
||||
return false, "Blocked is nil or missing"
|
||||
end
|
||||
if type(val) ~= "boolean" then
|
||||
return false, "Blocked is not a boolean"
|
||||
end
|
||||
if val == nil then return false, "Blocked is nil or missing" end
|
||||
if type(val) ~= "boolean" then return false, "Blocked is not a boolean" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -608,17 +488,10 @@ local function Init()
|
||||
---@return boolean, nil|string
|
||||
GetAbsorbed = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return false,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return false, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["absorbed"], ...)
|
||||
if val == nil then
|
||||
return false, "Absorbed is nil or missing"
|
||||
end
|
||||
if type(val) ~= "boolean" then
|
||||
return false, "Absorbed is not a boolean"
|
||||
end
|
||||
if val == nil then return false, "Absorbed is nil or missing" end
|
||||
if type(val) ~= "boolean" then return false, "Absorbed is not a boolean" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -640,17 +513,10 @@ local function Init()
|
||||
---@return boolean, nil|string
|
||||
GetCritical = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return false,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return false, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["critical"], ...)
|
||||
if val == nil then
|
||||
return false, "Critical is nil or missing"
|
||||
end
|
||||
if type(val) ~= "boolean" then
|
||||
return false, "Critical is not a boolean"
|
||||
end
|
||||
if val == nil then return false, "Critical is nil or missing" end
|
||||
if type(val) ~= "boolean" then return false, "Critical is not a boolean" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -670,17 +536,10 @@ local function Init()
|
||||
---@return boolean, nil|string
|
||||
GetGlancing = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return false,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return false, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["glancing"], ...)
|
||||
if val == nil then
|
||||
return false, "Glancing is nil or missing"
|
||||
end
|
||||
if type(val) ~= "boolean" then
|
||||
return false, "Glancing is not a boolean"
|
||||
end
|
||||
if val == nil then return false, "Glancing is nil or missing" end
|
||||
if type(val) ~= "boolean" then return false, "Glancing is not a boolean" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -700,17 +559,10 @@ local function Init()
|
||||
---@return boolean, nil|string
|
||||
GetCrushing = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return false,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return false, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["crushing"], ...)
|
||||
if val == nil then
|
||||
return false, "Crushing is nil or missing"
|
||||
end
|
||||
if type(val) ~= "boolean" then
|
||||
return false, "Crushing is not a boolean"
|
||||
end
|
||||
if val == nil then return false, "Crushing is nil or missing" end
|
||||
if type(val) ~= "boolean" then return false, "Crushing is not a boolean" end
|
||||
return val, nil
|
||||
end,
|
||||
--- Specific to subevents prefixed by:
|
||||
@@ -731,17 +583,10 @@ local function Init()
|
||||
---@return boolean, nil|string
|
||||
GetIsOffHand = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return false,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return false, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["isOffHand"], ...)
|
||||
if val == nil then
|
||||
return false, "IsOffHand is nil or missing"
|
||||
end
|
||||
if type(val) ~= "boolean" then
|
||||
return false, "IsOffHand is not a boolean"
|
||||
end
|
||||
if val == nil then return false, "IsOffHand is nil or missing" end
|
||||
if type(val) ~= "boolean" then return false, "IsOffHand is not a boolean" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -764,17 +609,10 @@ local function Init()
|
||||
---@return string, nil|string
|
||||
GetMissType = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return "",
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return "", string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["missType"], ...)
|
||||
if val == nil then
|
||||
return "", "MissType is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "MissType is not a string"
|
||||
end
|
||||
if val == nil then return "", "MissType is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "MissType is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -797,17 +635,10 @@ local function Init()
|
||||
--- return type is unconfirmed!
|
||||
GetAmountMissed = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["amountMissed"], ...)
|
||||
if val == nil then
|
||||
return 0, "AmountMissed is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "AmountMissed is not a number"
|
||||
end
|
||||
if val == nil then return 0, "AmountMissed is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "AmountMissed is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -830,17 +661,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetOverhealing = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["overhealing"], ...)
|
||||
if val == nil then
|
||||
return 0, "Overhealing is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "Overhealing is not a number"
|
||||
end
|
||||
if val == nil then return 0, "Overhealing is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "Overhealing is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -861,17 +685,10 @@ local function Init()
|
||||
---@return string, nil|string
|
||||
GetExtraGUID = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return "",
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return "", string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraGUID"], ...)
|
||||
if val == nil then
|
||||
return "", "ExtraGUID is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "ExtraGUID is not a string"
|
||||
end
|
||||
if val == nil then return "", "ExtraGUID is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "ExtraGUID is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -892,17 +709,10 @@ local function Init()
|
||||
---@return string, nil|string
|
||||
GetExtraName = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return "",
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return "", string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraName"], ...)
|
||||
if val == nil then
|
||||
return "", "ExtraName is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "ExtraName is not a string"
|
||||
end
|
||||
if val == nil then return "", "ExtraName is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "ExtraName is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -923,17 +733,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetExtraFlags = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraFlags"], ...)
|
||||
if val == nil then
|
||||
return 0, "ExtraFlags is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "ExtraFlags is not a number"
|
||||
end
|
||||
if val == nil then return 0, "ExtraFlags is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "ExtraFlags is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -954,17 +757,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetExtraRaidFlags = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraRaidFlags"], ...)
|
||||
if val == nil then
|
||||
return 0, "ExtraRaidFlags is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "ExtraRaidFlags is not a number"
|
||||
end
|
||||
if val == nil then return 0, "ExtraRaidFlags is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "ExtraRaidFlags is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -989,17 +785,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetExtraSpellID = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraSpellID"], ...)
|
||||
if val == nil then
|
||||
return 0, "ExtraSpellID is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "ExtraSpellID is not a number"
|
||||
end
|
||||
if val == nil then return 0, "ExtraSpellID is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "ExtraSpellID is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -1025,17 +814,10 @@ local function Init()
|
||||
---@return string, nil|string
|
||||
GetExtraSpellName = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return "",
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return "", string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraSpellName"], ...)
|
||||
if val == nil then
|
||||
return "", "extraSpellName is nil or missing"
|
||||
end
|
||||
if type(val) ~= "string" then
|
||||
return "", "extraSpellName is not a string"
|
||||
end
|
||||
if val == nil then return "", "extraSpellName is nil or missing" end
|
||||
if type(val) ~= "string" then return "", "extraSpellName is not a string" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -1061,17 +843,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetExtraSchool = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraSchool"], ...)
|
||||
if val == nil then
|
||||
return 0, "ExtraSchool is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "ExtraSchool is not a number"
|
||||
end
|
||||
if val == nil then return 0, "ExtraSchool is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "ExtraSchool is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -1092,17 +867,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetAbsorbedAmount = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["absorbedAmount"], ...)
|
||||
if val == nil then
|
||||
return 0, "AbsorbedAmount is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "AbsorbedAmount is not a number"
|
||||
end
|
||||
if val == nil then return 0, "AbsorbedAmount is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "AbsorbedAmount is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -1123,17 +891,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetOverEnergize = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["overEnergize"], ...)
|
||||
if val == nil then
|
||||
return 0, "OverEnergize is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "OverEnergize is not a number"
|
||||
end
|
||||
if val == nil then return 0, "OverEnergize is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "OverEnergize is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -1158,17 +919,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetPowerType = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["powerType"], ...)
|
||||
if val == nil then
|
||||
return 0, "PowerType is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "PowerType is not a number"
|
||||
end
|
||||
if val == nil then return 0, "PowerType is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "PowerType is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -1190,17 +944,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetExtraAmount = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraAmount"], ...)
|
||||
if val == nil then
|
||||
return 0, "ExtraAmount is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "ExtraAmount is not a number"
|
||||
end
|
||||
if val == nil then return 0, "ExtraAmount is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "ExtraAmount is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -1229,17 +976,10 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetExtraSpellId = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["extraSpellId"], ...)
|
||||
if val == nil then
|
||||
return 0, "ExtraSpellId is nil or missing"
|
||||
end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "ExtraSpellId is not a number"
|
||||
end
|
||||
if val == nil then return 0, "ExtraSpellId is nil or missing" end
|
||||
if type(val) ~= "number" then return 0, "ExtraSpellId is not a number" end
|
||||
return val, nil
|
||||
end,
|
||||
|
||||
@@ -1268,17 +1008,12 @@ local function Init()
|
||||
---@return number, nil|string
|
||||
GetExtraAuraType = function(...)
|
||||
local subevent, err = CLEUParser.GetSubevent(...)
|
||||
if err then
|
||||
return 0,
|
||||
string.format("Failed getting subevent due to: %s", err)
|
||||
end
|
||||
if err then return 0, string.format("Failed getting subevent due to: %s", err) end
|
||||
local val = select(CLEUEventInfo[subevent]["auraType"], ...)
|
||||
if val == nil then return 0, "AuraType is nil or missing" end
|
||||
if type(val) ~= "number" then
|
||||
return 0, "AuraType is not a number"
|
||||
end
|
||||
if type(val) ~= "number" then return 0, "AuraType is not a number" end
|
||||
return val, nil
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -1286,7 +1021,5 @@ local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("PLAYER_LOGIN")
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
frame:RegisterEvent("GUILD_ROSTER_UPDATE")
|
||||
frame:SetScript("OnEvent", function(self, event, ...)
|
||||
Init()
|
||||
end)
|
||||
frame:SetScript("OnEvent", function(self, event, ...) Init() end)
|
||||
Init()
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "CombatAlerter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.CombatAlerter = {}
|
||||
@@ -9,41 +9,127 @@ function shared.CombatAlerter.Init()
|
||||
local combatAlerterFrame = CreateFrame("Frame")
|
||||
combatAlerterFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
|
||||
combatAlerterFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
if not Heimdall_Data.config.combatAlerter.enabled then return end
|
||||
local destination, err = CLEUParser.GetDestName(...)
|
||||
if err then return end
|
||||
if destination ~= UnitName("player") then return end
|
||||
local source, err = CLEUParser.GetSourceName(...)
|
||||
if err then source = "unknown" end
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Combat log event received", ModuleName))
|
||||
end
|
||||
if not Heimdall_Data.config.combatAlerter.enabled then
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring combat event", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
---@type string|nil, string, string
|
||||
local err, source, destination
|
||||
|
||||
destination, err = CLEUParser.GetDestName(...)
|
||||
if err then
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Error getting destination: %s", ModuleName, err))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Combat event destination: %s", ModuleName, destination))
|
||||
end
|
||||
|
||||
if destination ~= UnitName("player") then
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Ignoring event - not targeted at player", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
source, err = CLEUParser.GetSourceName(...)
|
||||
if err then
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Error getting source, using 'unknown': %s", ModuleName, err))
|
||||
end
|
||||
source = "unknown"
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Combat event source: %s", ModuleName, source))
|
||||
end
|
||||
|
||||
if shared.stinkyTracker.stinkies and shared.stinkyTracker.stinkies[source] then
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Source is tracked stinky: %s (Already alerted: %s)",
|
||||
ModuleName,
|
||||
source,
|
||||
tostring(alerted[source] or false)
|
||||
)
|
||||
)
|
||||
end
|
||||
if alerted[source] then return end
|
||||
|
||||
alerted[source] = true
|
||||
local x, y = GetPlayerMapPosition("player")
|
||||
local zone, subZone = GetZoneText(), GetSubZoneText()
|
||||
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Player location: %s/%s at %.2f,%.2f",
|
||||
ModuleName,
|
||||
zone,
|
||||
subZone,
|
||||
x * 100,
|
||||
y * 100
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
SetMapToCurrentZone()
|
||||
SetMapByID(GetCurrentMapAreaID())
|
||||
local areaId = GetCurrentMapAreaID()
|
||||
|
||||
for _, channel in pairs(Heimdall_Data.config.combatAlerter.channels) do
|
||||
local locale = shared.GetLocaleForChannel(channel)
|
||||
local text = string.format(
|
||||
shared._L("combatAlerterInCombat", locale),
|
||||
source,
|
||||
shared._L("zone", locale),
|
||||
shared._L("subZone", locale),
|
||||
tostring(areaId),
|
||||
x * 100,
|
||||
y * 100
|
||||
)
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.combatAlerter.masterChannel,
|
||||
message = string.format("%s is attacking me in %s(%s) at %2.2f,%2.2f ",
|
||||
source,
|
||||
GetZoneText(), GetSubZoneText(),
|
||||
x * 100, y * 100
|
||||
),
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text,
|
||||
}
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Queuing alert message", ModuleName))
|
||||
shared.dumpTable(msg)
|
||||
end
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
end
|
||||
elseif Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Source not in stinky list, ignoring: %s", ModuleName, source))
|
||||
end
|
||||
end)
|
||||
|
||||
local combatTriggerFrame = CreateFrame("Frame")
|
||||
combatTriggerFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||
combatTriggerFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||
-- We want to only alert once per target per combat encounter
|
||||
-- Even a small throttle would probably spam too much here
|
||||
-- ....but maybe we can call it a 120 second throttle or something?
|
||||
-- We will see
|
||||
combatTriggerFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
if Heimdall_Data.config.combatAlerter.debug then
|
||||
print(string.format("[%s] Combat state changed: %s", ModuleName, event))
|
||||
if event == "PLAYER_REGEN_DISABLED" then
|
||||
print(string.format("[%s] Entered combat - Resetting alerts", ModuleName))
|
||||
else
|
||||
print(string.format("[%s] Left combat - Resetting alerts", ModuleName))
|
||||
end
|
||||
end
|
||||
alerted = {}
|
||||
end)
|
||||
|
||||
print("Heimdall - CombatAlerter loaded")
|
||||
if Heimdall_Data.config.combatAlerter.debug then print(string.format("[%s] Module initialized", ModuleName)) end
|
||||
print("[Heimdall] CombatAlerter loaded")
|
||||
end
|
||||
|
@@ -1,14 +1,20 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Commander"
|
||||
|
||||
local helpMessages = {
|
||||
ru = {
|
||||
"1) who - пишет вам никнеймы текущих врагов в отслеживаемых локациях по порядку и локацию.",
|
||||
"2) classes = пишет какие классы. (например 1 паладин 1 прист 1 рога.",
|
||||
"3) howmany - общее число врагов (например дуротар 4 . оргримар 2 ) ",
|
||||
"4) + - автоматическое приглашение в группу с дуельным рогой для сброса кд и общего сбора. ",
|
||||
"5) ++ - автоматическое приглашение в группу альянса. (если нужен рефрак)",
|
||||
"1) who - пишет вам никнеймы текущих врагов и локу.",
|
||||
"2) classes - покажет классы врагов и число.",
|
||||
"3) howmany - общее число врагов (дурик 4 . огри 2 ) ",
|
||||
"4) + - атоинвайт в сбор пати и сброса кд.",
|
||||
"5) ++ -автоинвайт в пати аликов (если нужен рефрак)",
|
||||
"6 ) note Никнейм текст - добавление заметки.",
|
||||
"7) note Никнейм - посмотреть последние заметки.",
|
||||
"8) note Никнейм 5 - посмотреть конкретную заметку.",
|
||||
"9) note Никнейм 1..5 - посмотреть заметки от 1 до 5",
|
||||
"10) note Никнейм delete 1 - удалить заметку номер 1",
|
||||
"11) note Никнейм delete 1..5 - удалить заметки 1 до 5",
|
||||
},
|
||||
en = {
|
||||
"1) who - reports currently tracked stinkies in orgrimmar and durotar",
|
||||
@@ -16,7 +22,13 @@ local helpMessages = {
|
||||
"3) howmany - reports stinkies grouped by zone",
|
||||
"4) + - automatically invites to group with duel rogue for cd reset",
|
||||
"5) ++ - automatically invites to alliance group",
|
||||
}
|
||||
"6) note <name> <note> - adds a note for the specified character.",
|
||||
"7) note <name> - lists the last N notes for the character.",
|
||||
"8) note <name> i - lists the i-th note for the character.",
|
||||
"9) note <name> i..j - lists notes from i to j for the character.",
|
||||
"10) note <name> delete i - deletes the i-th note for the character.",
|
||||
"11) note <name> delete i..j - deletes notes from i to j for the character.",
|
||||
},
|
||||
}
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
@@ -38,16 +50,12 @@ function shared.Commander.Init()
|
||||
if #currentChunk + #word + 1 <= size then
|
||||
currentChunk = currentChunk .. (currentChunk == "" and word or " " .. word)
|
||||
else
|
||||
if #currentChunk > 0 then
|
||||
ret[#ret + 1] = currentChunk
|
||||
end
|
||||
if #currentChunk > 0 then ret[#ret + 1] = currentChunk end
|
||||
currentChunk = word
|
||||
end
|
||||
end
|
||||
|
||||
if #currentChunk > 0 then
|
||||
ret[#ret + 1] = currentChunk
|
||||
end
|
||||
if #currentChunk > 0 then ret[#ret + 1] = currentChunk end
|
||||
|
||||
return ret
|
||||
end
|
||||
@@ -56,9 +64,7 @@ function shared.Commander.Init()
|
||||
local function Count(arr)
|
||||
local ret = {}
|
||||
for _, player in pairs(arr) do
|
||||
if Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
ret[player.zone] = (ret[player.zone] or 0) + 1
|
||||
end
|
||||
if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.zone] = (ret[player.zone] or 0) + 1 end
|
||||
end
|
||||
local text = {}
|
||||
for zone, count in pairs(ret) do
|
||||
@@ -71,6 +77,7 @@ function shared.Commander.Init()
|
||||
local function CountPartitioned(arr)
|
||||
local count = Count(arr)
|
||||
local text = {}
|
||||
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
|
||||
for _, line in pairs(Partition(strjoin(", ", unpack(count)), 200)) do
|
||||
text[#text + 1] = line
|
||||
end
|
||||
@@ -81,11 +88,19 @@ function shared.Commander.Init()
|
||||
local function Who(arr)
|
||||
local ret = {}
|
||||
for _, player in pairs(arr) do
|
||||
if Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
ret[#ret + 1] = string.format("%s/%s (%s) %s", player.name, player.class, player.zone,
|
||||
player.stinky and "(!!!!)" or "")
|
||||
if shared.Whoer.ShouldNotifyForZone(player.zone) then
|
||||
ret[#ret + 1] = string.format(
|
||||
"%s/%s (%s) %s",
|
||||
player.name,
|
||||
player.class,
|
||||
player.zone,
|
||||
player.stinky and "(!!!!)" or ""
|
||||
)
|
||||
end
|
||||
end
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Command result: %s", ModuleName, strjoin(", ", unpack(ret))))
|
||||
end
|
||||
return ret
|
||||
end
|
||||
---@param arr table<string, Player>
|
||||
@@ -93,8 +108,9 @@ function shared.Commander.Init()
|
||||
local function WhoPartitioned(arr)
|
||||
local who = Who(arr)
|
||||
local text = {}
|
||||
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
|
||||
for _, line in pairs(Partition(strjoin(", ", unpack(who)), 200)) do
|
||||
text[#text + 1] = line
|
||||
text[#text + 1] = "who: " .. line
|
||||
end
|
||||
return text
|
||||
end
|
||||
@@ -103,14 +119,15 @@ function shared.Commander.Init()
|
||||
local function CountClass(arr)
|
||||
local ret = {}
|
||||
for _, player in pairs(arr) do
|
||||
if Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
ret[player.class] = (ret[player.class] or 0) + 1
|
||||
end
|
||||
if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.class] = (ret[player.class] or 0) + 1 end
|
||||
end
|
||||
local text = {}
|
||||
for class, count in pairs(ret) do
|
||||
text[#text + 1] = string.format("%s: %d", class, count)
|
||||
end
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Message text: %s", ModuleName, strjoin(", ", unpack(text))))
|
||||
end
|
||||
return text
|
||||
end
|
||||
---@param arr table<string, Player>
|
||||
@@ -118,106 +135,211 @@ function shared.Commander.Init()
|
||||
local function CountClassPartitioned(arr)
|
||||
local countClass = CountClass(arr)
|
||||
local text = {}
|
||||
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
|
||||
for _, line in pairs(Partition(strjoin(", ", unpack(countClass)), 200)) do
|
||||
text[#text + 1] = line
|
||||
end
|
||||
return text
|
||||
end
|
||||
local function CountClassPartitionedStinkies()
|
||||
local res = CountClassPartitioned(HeimdallStinkies)
|
||||
if #res == 0 then
|
||||
return { "No stinkies found" }
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Executing: CountClassPartitionedStinkies", ModuleName))
|
||||
end
|
||||
local res = CountClassPartitioned(HeimdallStinkies)
|
||||
if #res == 0 then return { "No stinkies found" } end
|
||||
return res
|
||||
end
|
||||
local function WhoPartitionedStinkies()
|
||||
local res = WhoPartitioned(HeimdallStinkies)
|
||||
if #res == 0 then
|
||||
return { "No stinkies found" }
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Executing: WhoPartitionedStinkies", ModuleName))
|
||||
shared.dumpTable(HeimdallStinkies)
|
||||
end
|
||||
local res = WhoPartitioned(HeimdallStinkies)
|
||||
if #res == 0 then return { "No stinkies found" } end
|
||||
return res
|
||||
end
|
||||
local function CountPartitionedStinkies()
|
||||
local res = CountPartitioned(HeimdallStinkies)
|
||||
if #res == 0 then
|
||||
return { "No stinkies found" }
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Executing: CountPartitionedStinkies", ModuleName))
|
||||
end
|
||||
local res = CountPartitioned(HeimdallStinkies)
|
||||
if #res == 0 then return { "No stinkies found" } end
|
||||
return res
|
||||
end
|
||||
local function HelpRu() return helpMessages.ru end
|
||||
local function HelpEn() return helpMessages.en end
|
||||
local function HelpRu()
|
||||
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpRu", ModuleName)) end
|
||||
return helpMessages.ru
|
||||
end
|
||||
local function HelpEn()
|
||||
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpEn", ModuleName)) end
|
||||
return helpMessages.en
|
||||
end
|
||||
local groupInviteFrame = CreateFrame("Frame")
|
||||
groupInviteFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Event received", ModuleName)) end
|
||||
AcceptGroup()
|
||||
groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST")
|
||||
C_Timer.NewTimer(0.1, function()
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Click event triggered", ModuleName))
|
||||
end
|
||||
_G["StaticPopup1Button1"]:Click()
|
||||
end, 1)
|
||||
end)
|
||||
local function JoinGroup()
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] JoinGroup command received", ModuleName))
|
||||
end
|
||||
groupInviteFrame:RegisterEvent("PARTY_INVITE_REQUEST")
|
||||
C_Timer.NewTimer(10, function()
|
||||
groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST")
|
||||
end, 1)
|
||||
C_Timer.NewTimer(10, function() groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") end, 1)
|
||||
return { "+" }
|
||||
end
|
||||
local function LeaveGroup()
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] LeaveGroup command received", ModuleName))
|
||||
end
|
||||
LeaveParty()
|
||||
return {}
|
||||
end
|
||||
---@param target string
|
||||
local function FollowTarget(target)
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Following target: %s", ModuleName, target))
|
||||
end
|
||||
if not target then return end
|
||||
FollowUnit(target)
|
||||
return {}
|
||||
end
|
||||
|
||||
---@param args string[]
|
||||
local function MacroTarget(args)
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
|
||||
print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args))))
|
||||
end
|
||||
if #args < 2 or #args % 2 ~= 0 then
|
||||
if #args < 2 or #args % 2 ~= 0 then
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Invalid number of arguments for MacroTarget", ModuleName))
|
||||
end
|
||||
return {}
|
||||
end
|
||||
end
|
||||
table.remove(args, 1)
|
||||
|
||||
for i = 1, #args do
|
||||
local stinky = strtrim(args[i])
|
||||
local name = stinky:match("([^/]+)")
|
||||
local class = stinky:match("/([^ $]+)")
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Adding stinky: %s/%s", ModuleName, name, tostring(class)))
|
||||
end
|
||||
shared.stinkyTracker.stinkies[name] = {
|
||||
name = name,
|
||||
class = class or "unknown",
|
||||
seenAt = GetTime(),
|
||||
hostile = true,
|
||||
}
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
---@class Command
|
||||
---@field keywordRe string
|
||||
---@field commanderOnly boolean
|
||||
---@field callback fun(...: any): string[]
|
||||
|
||||
local commands = {
|
||||
{ keywordRe = "^who", commanderOnly = false, callback = WhoPartitionedStinkies },
|
||||
{ keywordRe = "^howmany", commanderOnly = false, callback = CountPartitionedStinkies },
|
||||
{ keywordRe = "^classes", commanderOnly = false, callback = CountClassPartitionedStinkies },
|
||||
{ keywordRe = "^help", commanderOnly = false, callback = HelpRu },
|
||||
{ keywordRe = "^helpen", commanderOnly = false, callback = HelpEn },
|
||||
{ keywordRe = "^joingroup", commanderOnly = false, callback = JoinGroup },
|
||||
{ keywordRe = "^leavegroup", commanderOnly = false, callback = LeaveGroup },
|
||||
{ keywordRe = "^follow", commanderOnly = false, callback = FollowTarget },
|
||||
{ keywordRe = "^who$", commanderOnly = false, callback = WhoPartitionedStinkies },
|
||||
{ keywordRe = "^howmany$", commanderOnly = false, callback = CountPartitionedStinkies },
|
||||
{ keywordRe = "^classes$", commanderOnly = false, callback = CountClassPartitionedStinkies },
|
||||
{ keywordRe = "^help$", commanderOnly = false, callback = HelpRu },
|
||||
{ keywordRe = "^helpen$", commanderOnly = false, callback = HelpEn },
|
||||
{ keywordRe = "^joingroup$", commanderOnly = false, callback = JoinGroup },
|
||||
{ keywordRe = "^leavegroup$", commanderOnly = false, callback = LeaveGroup },
|
||||
{ keywordRe = "^follow$", commanderOnly = false, callback = FollowTarget },
|
||||
{ keywordRe = "^macro", commanderOnly = false, callback = MacroTarget },
|
||||
}
|
||||
|
||||
local commanderChannelFrame = CreateFrame("Frame")
|
||||
commanderChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL")
|
||||
commanderChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
|
||||
if not Heimdall_Data.config.commander.enabled then return end
|
||||
--if Heimdall_Data.config.commander.debug then
|
||||
-- print(string.format("[%s] Event received", ModuleName))
|
||||
-- shared.dumpTable(Heimdall_Data.config.commander)
|
||||
--end
|
||||
if not Heimdall_Data.config.commander.enabled then
|
||||
--if Heimdall_Data.config.commander.debug then
|
||||
-- print(string.format("[%s] Module disabled, ignoring event", ModuleName))
|
||||
--end
|
||||
return
|
||||
end
|
||||
local channelId = select(6, ...)
|
||||
local _, channelname = GetChannelName(channelId)
|
||||
if channelname ~= Heimdall_Data.config.commander.masterChannel then return end
|
||||
local ok = false
|
||||
for _, channel in pairs(Heimdall_Data.config.commander.channels) do
|
||||
if channel == channelname then
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not ok then
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Channel name '%s' does not match any of the channels '%s'",
|
||||
ModuleName,
|
||||
channelname,
|
||||
table.concat(Heimdall_Data.config.commander.channels, ", ")
|
||||
)
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
sender = string.match(sender, "^[^-]+")
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Message from: %s", ModuleName, sender))
|
||||
shared.dumpTable(Heimdall_Data.config.commander)
|
||||
end
|
||||
|
||||
for _, command in ipairs(commands) do
|
||||
local enabled = Heimdall_Data.config.commander.commands[command.keywordRe] == true or false
|
||||
if enabled and
|
||||
(not command.commanderOnly
|
||||
or (command.commanderOnly
|
||||
and sender == Heimdall_Data.config.commander.commander)) then
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Command match: %s = %s", ModuleName, command.keywordRe, tostring(enabled)))
|
||||
end
|
||||
if
|
||||
enabled
|
||||
and (
|
||||
not command.commanderOnly
|
||||
or (command.commanderOnly and sender == Heimdall_Data.config.commander.commander)
|
||||
)
|
||||
then
|
||||
if msg:match(command.keywordRe) then
|
||||
local messages = command.callback({ strsplit(" ", msg) })
|
||||
---@diagnostic disable-next-line: redundant-parameter Currently luals does not support variadic functions as a @field
|
||||
local messages = command.callback({ strsplit(",", msg) })
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
print(string.format("[%s] Messages to send: %s", ModuleName, strjoin(", ", unpack(messages))))
|
||||
end
|
||||
for _, message in ipairs(messages) do
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
local returnmsg = {
|
||||
channel = "C",
|
||||
data = channelname,
|
||||
message = message
|
||||
message = message,
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
print(string.format("[%s] Queuing message", ModuleName))
|
||||
shared.dumpTable(msg)
|
||||
end
|
||||
--table.insert(shared.messenger.queue, msg)
|
||||
table.insert(shared.networkMessenger.queue, returnmsg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - Commander loaded")
|
||||
print("[Heimdall] Commander module loaded")
|
||||
end
|
||||
|
2192
Modules/Config.lua
2192
Modules/Config.lua
File diff suppressed because it is too large
Load Diff
7
Modules/Configurator.lua
Normal file
7
Modules/Configurator.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
local ModuleName = "Configurator"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Configurator = {}
|
||||
function shared.Configurator.Init() print(string.format("[Heimdall] %s module loaded", ModuleName)) end
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "DeathReporter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.DeathReporter = {}
|
||||
@@ -14,64 +14,163 @@ function shared.DeathReporter.Init()
|
||||
---@param destination string
|
||||
---@param spellName string
|
||||
local function RegisterDeath(source, destination, spellName)
|
||||
if not Heimdall_Data.config.deathReporter.enabled then return end
|
||||
if recentDeaths[destination]
|
||||
and GetTime() - recentDeaths[destination] < Heimdall_Data.config.deathReporter.throttle then
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Processing death event - Source: %s, Target: %s, Spell: %s",
|
||||
ModuleName,
|
||||
source,
|
||||
destination,
|
||||
spellName
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
if not Heimdall_Data.config.deathReporter.enabled then
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring death event", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if recentDuels[destination]
|
||||
and GetTime() - recentDuels[destination] < Heimdall_Data.config.deathReporter.duelThrottle then
|
||||
print(string.format("Cancelling death reports for %s and %s because of recent duel", source, destination))
|
||||
return
|
||||
if
|
||||
recentDeaths[destination]
|
||||
and GetTime() - recentDeaths[destination] < Heimdall_Data.config.deathReporter.throttle
|
||||
then
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
local timeLeft = Heimdall_Data.config.deathReporter.throttle - (GetTime() - recentDeaths[destination])
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Death report throttled for %s (%.1f seconds remaining)",
|
||||
ModuleName,
|
||||
destination,
|
||||
timeLeft
|
||||
)
|
||||
)
|
||||
end
|
||||
if recentDuels[source]
|
||||
and GetTime() - recentDuels[source] < Heimdall_Data.config.deathReporter.duelThrottle then
|
||||
print(string.format("Cancelling death reports for %s and %s because of recent duel", source, destination))
|
||||
return
|
||||
end
|
||||
|
||||
if
|
||||
recentDuels[destination]
|
||||
and GetTime() - recentDuels[destination] < Heimdall_Data.config.deathReporter.duelThrottle
|
||||
then
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Ignoring death report - Recent duel detected for target: %s",
|
||||
ModuleName,
|
||||
destination
|
||||
)
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if
|
||||
recentDuels[source]
|
||||
and GetTime() - recentDuels[source] < Heimdall_Data.config.deathReporter.duelThrottle
|
||||
then
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Ignoring death report - Recent duel detected for source: %s",
|
||||
ModuleName,
|
||||
source
|
||||
)
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Recording death for %s", ModuleName, destination))
|
||||
end
|
||||
recentDeaths[destination] = GetTime()
|
||||
|
||||
C_Timer.NewTimer(3, function()
|
||||
if recentDuels[destination]
|
||||
and GetTime() - recentDuels[destination] < Heimdall_Data.config.deathReporter.duelThrottle then
|
||||
print(string.format("Cancelling death reports for %s and %s because of recent duel", source, destination))
|
||||
return
|
||||
if
|
||||
recentDuels[destination]
|
||||
and GetTime() - recentDuels[destination] < Heimdall_Data.config.deathReporter.duelThrottle
|
||||
then
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Cancelling delayed death report - Recent duel detected for: %s",
|
||||
ModuleName,
|
||||
destination
|
||||
)
|
||||
)
|
||||
end
|
||||
if recentDuels[source]
|
||||
and GetTime() - recentDuels[source] < Heimdall_Data.config.deathReporter.duelThrottle then
|
||||
print(string.format("Cancelling death reports for %s and %s because of recent duel", source, destination))
|
||||
return
|
||||
end
|
||||
|
||||
local zone = Heimdall_Data.config.deathReporter.zoneOverride
|
||||
if zone == nil or zone == "" then
|
||||
zone = string.format("%s (%s)", GetZoneText(), GetSubZoneText())
|
||||
if
|
||||
recentDuels[source]
|
||||
and GetTime() - recentDuels[source] < Heimdall_Data.config.deathReporter.duelThrottle
|
||||
then
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Cancelling delayed death report - Recent duel detected for: %s",
|
||||
ModuleName,
|
||||
source
|
||||
)
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local text = string.format("%s killed %s with %s in %s",
|
||||
tostring(source),
|
||||
tostring(destination),
|
||||
tostring(spellName),
|
||||
tostring(zone))
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Sending death report - %s killed %s with %s",
|
||||
ModuleName,
|
||||
source,
|
||||
destination,
|
||||
spellName
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
local zone, subzone = GetZoneText() or "Unknown", GetSubZoneText() or "Unknown"
|
||||
if Heimdall_Data.config.spotter.zoneOverride then
|
||||
zone = Heimdall_Data.config.spotter.zoneOverride or ""
|
||||
subzone = ""
|
||||
end
|
||||
|
||||
local x, y = GetPlayerMapPosition("player")
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Player coordinates: %.2f, %.2f", ModuleName, x * 100, y * 100))
|
||||
end
|
||||
SetMapToCurrentZone()
|
||||
SetMapByID(GetCurrentMapAreaID())
|
||||
local zoneId = GetCurrentMapAreaID()
|
||||
|
||||
for _, channel in pairs(Heimdall_Data.config.deathReporter.channels) do
|
||||
local locale = shared.GetLocaleForChannel(channel)
|
||||
local text = string.format(
|
||||
shared._L("killed", locale),
|
||||
source,
|
||||
destination,
|
||||
shared._L(spellName, locale),
|
||||
shared._L(zone, locale),
|
||||
shared._L(subzone, locale),
|
||||
zoneId,
|
||||
x * 100,
|
||||
y * 100
|
||||
)
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.deathReporter.notifyChannel,
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text,
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
|
||||
if Heimdall_Data.config.deathReporter.doWhisper then
|
||||
for _, name in pairs(Heimdall_Data.config.whisperNotify) do
|
||||
local msg = {
|
||||
channel = "WHISPER",
|
||||
data = name,
|
||||
message = text,
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Queuing death report message", ModuleName))
|
||||
shared.dumpTable(msg)
|
||||
end
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -79,18 +178,37 @@ function shared.DeathReporter.Init()
|
||||
local cleuFrame = CreateFrame("Frame")
|
||||
cleuFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
|
||||
cleuFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
-- if Heimdall_Data.config.deathReporter.debug then
|
||||
-- print(string.format("[%s] Received combat log event", ModuleName))
|
||||
-- end
|
||||
if not Heimdall_Data.config.deathReporter.enabled then return end
|
||||
local overkill, err = CLEUParser.GetOverkill(...)
|
||||
local overkill, source, destination, spellName, sourceGUID, destinationGUID, err
|
||||
overkill, err = CLEUParser.GetOverkill(...)
|
||||
if not err and overkill > 0 then
|
||||
local source, err = CLEUParser.GetSourceName(...)
|
||||
if err then source = "unknown" end
|
||||
local destination, err = CLEUParser.GetDestName(...)
|
||||
if err then destination = "unknown" end
|
||||
local spellName, err = CLEUParser.GetSpellName(...)
|
||||
if err then spellName = "unknown" end
|
||||
local sourceGUID, err = CLEUParser.GetSourceGUID(...)
|
||||
source, err = CLEUParser.GetSourceName(...)
|
||||
if err then
|
||||
source = "unknown"
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Error getting source name", ModuleName))
|
||||
end
|
||||
end
|
||||
destination, err = CLEUParser.GetDestName(...)
|
||||
if err then
|
||||
destination = "unknown"
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Error getting destination name", ModuleName))
|
||||
end
|
||||
end
|
||||
spellName, err = CLEUParser.GetSpellName(...)
|
||||
if err then
|
||||
spellName = "unknown"
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Error getting spell name", ModuleName))
|
||||
end
|
||||
end
|
||||
sourceGUID, err = CLEUParser.GetSourceGUID(...)
|
||||
if err or not string.match(sourceGUID, "Player") then return end
|
||||
local destinationGUID, err = CLEUParser.GetDestGUID(...)
|
||||
destinationGUID, err = CLEUParser.GetDestGUID(...)
|
||||
if err or not string.match(destinationGUID, "Player") then return end
|
||||
RegisterDeath(source, destination, spellName)
|
||||
end
|
||||
@@ -101,16 +219,34 @@ function shared.DeathReporter.Init()
|
||||
systemMessageFrame:SetScript("OnEvent", function(self, event, msg)
|
||||
if not Heimdall_Data.config.deathReporter.enabled then return end
|
||||
local source, destination = string.match(msg, "([^ ]+) has defeated ([^ ]+) in a duel")
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Received system message: %s", ModuleName, msg))
|
||||
print(
|
||||
string.format("[%s] Source: %s, Destination: %s", ModuleName, tostring(source), tostring(destination))
|
||||
)
|
||||
end
|
||||
if not source or not destination then return end
|
||||
source = string.match(source, "([^-]+)")
|
||||
destination = string.match(destination, "([^-]+)")
|
||||
if source and destination then
|
||||
print(string.format("Detected duel between %s and %s", source, destination))
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Detected duel between %s and %s", ModuleName, source, destination))
|
||||
end
|
||||
local now = GetTime()
|
||||
recentDuels[source] = now
|
||||
recentDuels[destination] = now
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - DeathReporter loaded")
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Module initialized with throttle: %.1fs, duel throttle: %.1fs",
|
||||
ModuleName,
|
||||
Heimdall_Data.config.deathReporter.throttle,
|
||||
Heimdall_Data.config.deathReporter.duelThrottle
|
||||
)
|
||||
)
|
||||
end
|
||||
print("[Heimdall] DeathReporter loaded")
|
||||
end
|
||||
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Dueler"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Dueler = {}
|
||||
@@ -8,18 +8,48 @@ function shared.Dueler.Init()
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("DUEL_REQUESTED")
|
||||
frame:SetScript("OnEvent", function(self, event, sender)
|
||||
if not Heimdall_Data.config.dueler.enabled then return end
|
||||
if Heimdall_Data.config.dueler.debug then
|
||||
print(string.format("[%s] Duel request received from: %s", ModuleName, sender))
|
||||
end
|
||||
if not Heimdall_Data.config.dueler.enabled then
|
||||
if Heimdall_Data.config.dueler.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring duel request", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.dueler.debug then
|
||||
print(string.format("[%s] Checking if sender '%s' is in agents list", ModuleName, sender))
|
||||
end
|
||||
|
||||
local allow = Heimdall_Data.config.agents[sender]
|
||||
if allow then
|
||||
print("Heimdall - Dueler - Accepting duel from " .. sender)
|
||||
if Heimdall_Data.config.dueler.debug then
|
||||
print(string.format("[%s] Accepting duel from trusted agent: %s", ModuleName, sender))
|
||||
end
|
||||
AcceptDuel()
|
||||
else
|
||||
if Heimdall_Data.config.dueler.autoDecline then
|
||||
print("Heimdall - Dueler - Auto declining duel from " .. sender)
|
||||
if Heimdall_Data.config.dueler.declineOther then
|
||||
if Heimdall_Data.config.dueler.debug then
|
||||
print(string.format("[%s] Auto-declining duel from untrusted sender: %s", ModuleName, sender))
|
||||
end
|
||||
CancelDuel()
|
||||
else
|
||||
if Heimdall_Data.config.dueler.debug then
|
||||
print(string.format("[%s] Leaving duel request from %s for manual response", ModuleName, sender))
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - Dueler loaded")
|
||||
if Heimdall_Data.config.dueler.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Module initialized with auto-decline: %s",
|
||||
ModuleName,
|
||||
tostring(Heimdall_Data.config.dueler.declineOther)
|
||||
)
|
||||
)
|
||||
end
|
||||
print("[Heimdall] Dueler loaded")
|
||||
end
|
||||
|
@@ -1,6 +1,5 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
|
||||
if not shared.dumpTable then
|
||||
---@param table table
|
||||
@@ -10,15 +9,13 @@ if not shared.dumpTable then
|
||||
print(tostring(table))
|
||||
return
|
||||
end
|
||||
if depth == nil then
|
||||
depth = 0
|
||||
end
|
||||
if (depth > 200) then
|
||||
if depth == nil then depth = 0 end
|
||||
if depth > 200 then
|
||||
print("Error: Depth > 200 in dumpTable()")
|
||||
return
|
||||
end
|
||||
for k, v in pairs(table) do
|
||||
if (type(v) == "table") then
|
||||
if type(v) == "table" then
|
||||
print(string.rep(" ", depth) .. k .. ":")
|
||||
shared.dumpTable(v, depth + 1)
|
||||
else
|
||||
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Echoer"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Echoer = {}
|
||||
@@ -8,29 +8,51 @@ function shared.Echoer.Init()
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("CHAT_MSG_CHANNEL")
|
||||
frame:SetScript("OnEvent", function(self, event, msg, sender, ...)
|
||||
if not Heimdall_Data.config.echoer.enabled then return end
|
||||
--if Heimdall_Data.config.echoer.debug then
|
||||
-- print(string.format("[%s] Channel message received from: %s", ModuleName, sender))
|
||||
--end
|
||||
|
||||
if not Heimdall_Data.config.echoer.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 = ""
|
||||
---@type any[]
|
||||
local channels = { GetChannelList() }
|
||||
for i = 1, #channels, 2 do
|
||||
---@type number
|
||||
local id = channels[i]
|
||||
---@type string
|
||||
local name = channels[i + 1]
|
||||
if id == channelId then
|
||||
channelname = name
|
||||
local _, channelname = GetChannelName(channelId)
|
||||
local ok = false
|
||||
for _, channel in pairs(Heimdall_Data.config.echoer.channels) do
|
||||
if channel == channelname then
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if channelname ~= Heimdall_Data.config.echoer.masterChannel then return end
|
||||
if not ok then
|
||||
if Heimdall_Data.config.echoer.debug then
|
||||
print(string.format("[%s] Channel name does not match any of the channels", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if Heimdall_Data.config.echoer.debug then
|
||||
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
|
||||
shared.dumpTable(Heimdall_Data.config.echoer)
|
||||
end
|
||||
|
||||
if string.find(msg, "^" .. Heimdall_Data.config.echoer.prefix) then
|
||||
local msg = string.sub(msg, string.len(Heimdall_Data.config.echoer.prefix) + 1)
|
||||
SendChatMessage(msg, "SAY")
|
||||
if Heimdall_Data.config.echoer.debug then
|
||||
print(string.format("[%s] Found echo command in message: %s", ModuleName, msg))
|
||||
end
|
||||
local echomsg = string.sub(msg, string.len(Heimdall_Data.config.echoer.prefix) + 1)
|
||||
if Heimdall_Data.config.echoer.debug then
|
||||
print(string.format("[%s] Echoing message: %s", ModuleName, echomsg))
|
||||
end
|
||||
SendChatMessage(echomsg, "SAY")
|
||||
elseif Heimdall_Data.config.echoer.debug then
|
||||
print(string.format("[%s] Message does not start with echo prefix", ModuleName))
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - Echoer loaded")
|
||||
if Heimdall_Data.config.echoer.debug then print(string.format("[%s] Module initialized", ModuleName)) end
|
||||
print("[Heimdall] Echoer loaded")
|
||||
end
|
||||
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Emoter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Emoter = {}
|
||||
@@ -8,28 +8,52 @@ function shared.Emoter.Init()
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("CHAT_MSG_CHANNEL")
|
||||
frame:SetScript("OnEvent", function(self, event, msg, sender, ...)
|
||||
if not Heimdall_Data.config.emoter.enabled then return end
|
||||
--if Heimdall_Data.config.emoter.debug then
|
||||
-- print(string.format("[%s] Channel message received from: %s", ModuleName, sender))
|
||||
--end
|
||||
|
||||
if not Heimdall_Data.config.emoter.enabled then
|
||||
--if Heimdall_Data.config.emoter.debug then
|
||||
-- print(string.format("[%s] Module disabled, ignoring message", ModuleName))
|
||||
--end
|
||||
return
|
||||
end
|
||||
|
||||
local channelId = select(6, ...)
|
||||
local channelname = ""
|
||||
---@type any[]
|
||||
local channels = { GetChannelList() }
|
||||
for i = 1, #channels, 2 do
|
||||
---@type number
|
||||
local id = channels[i]
|
||||
---@type string
|
||||
local name = channels[i + 1]
|
||||
if id == channelId then
|
||||
channelname = name
|
||||
local _, channelname = GetChannelName(channelId)
|
||||
local ok = false
|
||||
for _, channel in pairs(Heimdall_Data.config.emoter.channels) do
|
||||
if channel == channelname then
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not ok then
|
||||
if Heimdall_Data.config.emoter.debug then
|
||||
print(string.format("[%s] Channel name does not match any of the channels", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if channelname ~= Heimdall_Data.config.emoter.masterChannel then return end
|
||||
if Heimdall_Data.config.emoter.debug then
|
||||
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
|
||||
shared.dumpTable(Heimdall_Data.config.emoter)
|
||||
end
|
||||
|
||||
if string.find(msg, "^" .. Heimdall_Data.config.emoter.prefix) then
|
||||
if Heimdall_Data.config.emoter.debug then
|
||||
print(string.format("[%s] Found emote command in message: %s", ModuleName, msg))
|
||||
end
|
||||
local emote = string.sub(msg, string.len(Heimdall_Data.config.emoter.prefix) + 1)
|
||||
if Heimdall_Data.config.emoter.debug then
|
||||
print(string.format("[%s] Performing emote: %s", ModuleName, emote))
|
||||
end
|
||||
DoEmote(emote)
|
||||
elseif Heimdall_Data.config.emoter.debug then
|
||||
print(string.format("[%s] Message does not start with emote prefix", ModuleName))
|
||||
end
|
||||
end)
|
||||
print("Heimdall - Emoter loaded")
|
||||
|
||||
if Heimdall_Data.config.emoter.debug then print(string.format("[%s] Module initialized", ModuleName)) end
|
||||
print("[Heimdall] Emoter loaded")
|
||||
end
|
||||
|
@@ -1,59 +1,134 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Inviter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Inviter = {}
|
||||
function shared.Inviter.Init()
|
||||
-- Fallback for old config
|
||||
if type(Heimdall_Data.config.inviter.listeningChannel) == "string" then
|
||||
Heimdall_Data.config.inviter.listeningChannel = {
|
||||
[Heimdall_Data.config.inviter.listeningChannel] = true,
|
||||
}
|
||||
end
|
||||
---@type Timer
|
||||
local updateTimer = nil
|
||||
|
||||
local function FixGroup()
|
||||
if not IsInRaid() then ConvertToRaid() end
|
||||
if Heimdall_Data.config.inviter.allAssist then SetEveryoneIsAssistant() end
|
||||
--shared.dumpTable(Heimdall_Data.config.inviter)
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Checking and fixing group configuration", ModuleName))
|
||||
end
|
||||
|
||||
if not IsInRaid() then
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Converting party to raid", ModuleName))
|
||||
end
|
||||
ConvertToRaid()
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.inviter.allAssist then
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Setting all members to assistant", ModuleName))
|
||||
end
|
||||
SetEveryoneIsAssistant()
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.inviter.agentsAssist then
|
||||
--shared.dumpTable(Heimdall_Data.config.agents)
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
local agentCount = 0
|
||||
for _ in pairs(Heimdall_Data.config.agents) do
|
||||
agentCount = agentCount + 1
|
||||
end
|
||||
print(string.format("[%s] Processing %d agents for assistant promotion", ModuleName, agentCount))
|
||||
end
|
||||
|
||||
for name, _ in pairs(Heimdall_Data.config.agents) do
|
||||
if UnitInParty(name)
|
||||
and not UnitIsGroupLeader(name)
|
||||
and not UnitIsRaidOfficer(name) then
|
||||
print("Promoting " .. name .. " to assistant")
|
||||
if UnitInParty(name) and not UnitIsGroupLeader(name) and not UnitIsRaidOfficer(name) then
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Promoting agent to assistant: %s", ModuleName, name))
|
||||
end
|
||||
PromoteToAssistant(name, true)
|
||||
elseif Heimdall_Data.config.inviter.debug then
|
||||
if not UnitInParty(name) then
|
||||
print(string.format("[%s] Agent not in party: %s", ModuleName, name))
|
||||
elseif UnitIsGroupLeader(name) then
|
||||
print(string.format("[%s] Agent is already leader: %s", ModuleName, name))
|
||||
elseif UnitIsRaidOfficer(name) then
|
||||
print(string.format("[%s] Agent is already assistant: %s", ModuleName, name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local framePool = {}
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Group configuration update complete", ModuleName))
|
||||
end
|
||||
end
|
||||
|
||||
---@param name string
|
||||
local function OverlayKickButtonElvUI(name)
|
||||
---@return Frame?
|
||||
local function FindPlayerRaidFrame(name)
|
||||
for group = 1, 8 do
|
||||
for player = 1, 5 do
|
||||
local button = _G[string.format("ElvUF_RaidGroup%dUnitButton%d", group, player)]
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] button = %s", ModuleName, tostring(button)))
|
||||
end
|
||||
|
||||
local unitName = button and button.unit and UnitName(button.unit)
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] unitName = %s", ModuleName, tostring(unitName)))
|
||||
end
|
||||
if unitName == name then
|
||||
local overlayButton = framePool[button.unit] or
|
||||
CreateFrame("Button",
|
||||
string.format("HeimdallKickButton%s", button.unit, button, "SecureActionButtonTemplate"))
|
||||
framePool[button.unit] = overlayButton
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] unitName == name", ModuleName))
|
||||
end
|
||||
return button
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
overlayButton:SetSize(button.UNIT_WIDTH/2, button.UNIT_HEIGHT/2)
|
||||
overlayButton:SetPoint("CENTER", button, "CENTER", 0, 0)
|
||||
overlayButton:SetNormalTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon")
|
||||
overlayButton:SetHighlightTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon")
|
||||
overlayButton:SetPushedTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon")
|
||||
overlayButton:SetDisabledTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon")
|
||||
overlayButton:SetAlpha(0.5)
|
||||
overlayButton:Show()
|
||||
overlayButton:SetScript("OnClick", function()
|
||||
local framePool = {}
|
||||
local playerButtons = {}
|
||||
setmetatable(playerButtons, { __mode = "kv" })
|
||||
---@param players string[]
|
||||
local function OverlayKickButtons(players)
|
||||
for _, frame in pairs(framePool) do
|
||||
frame:Hide()
|
||||
end
|
||||
for _, name in pairs(players) do
|
||||
local frame = FindPlayerRaidFrame(name)
|
||||
if frame then
|
||||
playerButtons[name] = frame
|
||||
-- All of these are ELVUI specific so they won't be in our meta...
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
local button = framePool[frame.unit]
|
||||
or CreateFrame(
|
||||
"Button",
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
string.format("HeimdallKickButton%s", frame.unit, frame, "SecureActionButtonTemplate")
|
||||
)
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
framePool[frame.unit] = button
|
||||
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
button:SetSize(frame.UNIT_WIDTH / 2, frame.UNIT_HEIGHT / 2)
|
||||
button:SetPoint("CENTER", frame, "CENTER", 0, 0)
|
||||
button:SetNormalTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon")
|
||||
button:SetHighlightTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon")
|
||||
button:SetPushedTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon")
|
||||
button:SetDisabledTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon")
|
||||
button:SetAlpha(0.5)
|
||||
button:Show()
|
||||
button:SetScript("OnClick", function()
|
||||
UninviteUnit(name)
|
||||
overlayButton:Hide()
|
||||
button:Hide()
|
||||
end)
|
||||
-- button:SetAttribute("type", "macro")
|
||||
-- button:SetAttribute("macrotext", "/kick " .. unit)
|
||||
return
|
||||
else
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Frame for player %s not found", ModuleName, name))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -77,38 +152,50 @@ function shared.Inviter.Init()
|
||||
groupMembers[name] = now
|
||||
else
|
||||
local online = UnitIsConnected(unit)
|
||||
if online then
|
||||
groupMembers[name] = now
|
||||
end
|
||||
if online then groupMembers[name] = now end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local afkPlayers = {}
|
||||
for name, time in pairs(groupMembers) do
|
||||
if time < now - Heimdall_Data.config.inviter.afkThreshold then
|
||||
print(string.format("Kicking %s for being offline", name))
|
||||
-- Blyat this is protected...
|
||||
-- UninviteUnit(name)
|
||||
OverlayKickButtonElvUI(name)
|
||||
end
|
||||
if not UnitInParty(name) then
|
||||
print(string.format("%s no longer in party", name))
|
||||
groupMembers[name] = nil
|
||||
else
|
||||
if time < now - Heimdall_Data.config.inviter.afkThreshold then
|
||||
print(string.format("Kicking %s for being offline", name))
|
||||
afkPlayers[#afkPlayers + 1] = name
|
||||
-- Blyat this is protected...
|
||||
-- UninviteUnit(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
OverlayKickButtons(afkPlayers)
|
||||
end
|
||||
local function Tick()
|
||||
CleanGroups()
|
||||
C_Timer.NewTimer(Heimdall_Data.config.inviter.cleanupInterval, Tick, 1)
|
||||
end
|
||||
Tick()
|
||||
|
||||
local inviterGroupFrame = CreateFrame("Frame")
|
||||
inviterGroupFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
|
||||
inviterGroupFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
if not Heimdall_Data.config.inviter.enabled then return end
|
||||
if not UnitIsGroupLeader("player") then return end
|
||||
local groupRosterUpdateFrame = CreateFrame("Frame")
|
||||
groupRosterUpdateFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
|
||||
groupRosterUpdateFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Event received: %s", ModuleName, event))
|
||||
end
|
||||
|
||||
if not Heimdall_Data.config.inviter.enabled then
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring event", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Group roster changed - Checking configuration", ModuleName))
|
||||
end
|
||||
if updateTimer then updateTimer:Cancel() end
|
||||
updateTimer = C_Timer.NewTimer(Heimdall_Data.config.inviter.throttle, FixGroup)
|
||||
end)
|
||||
@@ -116,24 +203,61 @@ function shared.Inviter.Init()
|
||||
local inviterChannelFrame = CreateFrame("Frame")
|
||||
inviterChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL")
|
||||
inviterChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
|
||||
--if Heimdall_Data.config.inviter.debug then
|
||||
-- print(string.format("[%s] Chat message received: %s", ModuleName, msg))
|
||||
-- shared.dumpTable(Heimdall_Data.config.inviter)
|
||||
--end
|
||||
if not Heimdall_Data.config.inviter.enabled then return end
|
||||
local channelId = select(6, ...)
|
||||
local channelname = ""
|
||||
---@type any[]
|
||||
local channels = { GetChannelList() }
|
||||
for i = 1, #channels, 2 do
|
||||
---@type number
|
||||
local id = channels[i]
|
||||
---@type string
|
||||
local name = channels[i + 1]
|
||||
if id == channelId then
|
||||
channelname = name
|
||||
local _, channelname = GetChannelName(channelId)
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Channel name: %s", ModuleName, channelname))
|
||||
end
|
||||
|
||||
local ok = false
|
||||
for _, channel in pairs(Heimdall_Data.config.inviter.channels) do
|
||||
if channel == channelname then
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if channelname ~= Heimdall_Data.config.inviter.listeningChannel then return end
|
||||
if msg == Heimdall_Data.config.inviter.keyword then InviteUnit(sender) end
|
||||
if not ok then
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Channel name does not match any of the channels", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if msg == Heimdall_Data.config.inviter.keyword then
|
||||
if Heimdall_Data.config.inviter.debug then print(string.format("[%s] Inviting %s", ModuleName, sender)) end
|
||||
InviteUnit(sender)
|
||||
else
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Message does not match keyword", ModuleName))
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - Inviter loaded")
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Module initialized - All assist: %s, Agents assist: %s",
|
||||
ModuleName,
|
||||
tostring(Heimdall_Data.config.inviter.allAssist),
|
||||
tostring(Heimdall_Data.config.inviter.agentsAssist)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Module initialized - All assist: %s, Agents assist: %s",
|
||||
ModuleName,
|
||||
tostring(Heimdall_Data.config.inviter.allAssist),
|
||||
tostring(Heimdall_Data.config.inviter.agentsAssist)
|
||||
)
|
||||
)
|
||||
end
|
||||
print("[Heimdall] Inviter loaded")
|
||||
end
|
||||
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Macroer"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Macroer = {}
|
||||
@@ -11,22 +11,40 @@ function shared.Macroer.Init()
|
||||
---@field seenAt number
|
||||
---@field hostile boolean
|
||||
|
||||
---@type table<string, stinky>
|
||||
local recentStinkies = {}
|
||||
|
||||
local function FindOrCreateMacro(macroName)
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Finding or creating macro: %s", ModuleName, macroName))
|
||||
end
|
||||
local idx = GetMacroIndexByName(macroName)
|
||||
if idx == 0 then
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Creating new macro: %s", ModuleName, macroName))
|
||||
end
|
||||
CreateMacro(macroName, "INV_Misc_QuestionMark", "")
|
||||
end
|
||||
idx = GetMacroIndexByName(macroName)
|
||||
if Heimdall_Data.config.macroer.debug then print(string.format("[%s] Macro index: %d", ModuleName, idx)) end
|
||||
return idx
|
||||
end
|
||||
|
||||
---@param stinkies table<string, stinky>
|
||||
local function FixMacro(stinkies)
|
||||
if not Heimdall_Data.config.macroer.enabled then return end
|
||||
if InCombatLockdown() then return end
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Fixing macro with %d stinkies", ModuleName, #stinkies))
|
||||
end
|
||||
if not Heimdall_Data.config.macroer.enabled then
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Module disabled, skipping macro update", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if InCombatLockdown() then
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] In combat, skipping macro update", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local priorityMap = {}
|
||||
for priority, className in ipairs(Heimdall_Data.config.macroer.priority) do
|
||||
priorityMap[className] = priority
|
||||
@@ -35,7 +53,11 @@ function shared.Macroer.Init()
|
||||
|
||||
local sortedStinkies = {}
|
||||
for _, stinky in pairs(stinkies) do
|
||||
table.insert(sortedStinkies, stinky)
|
||||
if not Heimdall_Data.config.agents[stinky.name] then sortedStinkies[#sortedStinkies + 1] = stinky end
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Processing %d non-agent stinkies", ModuleName, #sortedStinkies))
|
||||
end
|
||||
|
||||
table.sort(sortedStinkies, function(a, b)
|
||||
@@ -44,22 +66,36 @@ function shared.Macroer.Init()
|
||||
return aPriority > bPriority
|
||||
end)
|
||||
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Sorted stinkies: %d", ModuleName, #sortedStinkies))
|
||||
shared.dumpTable(sortedStinkies)
|
||||
end
|
||||
local lines = { "/targetenemy" }
|
||||
for _, stinky in pairs(sortedStinkies) do
|
||||
if stinky.seenAt > GetTime() - 600 then
|
||||
print(string.format("Macroing %s", stinky.name))
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Adding target macro for: %s", ModuleName, stinky.name))
|
||||
end
|
||||
lines[#lines + 1] = string.format("/tar %s", stinky.name)
|
||||
end
|
||||
end
|
||||
|
||||
local idx = FindOrCreateMacro("HeimdallTarget")
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local body = strjoin("\n", unpack(lines))
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Updating macro with %d lines", ModuleName, #lines))
|
||||
end
|
||||
EditMacro(idx, "HeimdallTarget", "INV_Misc_QuestionMark", body)
|
||||
end
|
||||
|
||||
shared.stinkyTracker.stinkies:onChange(function(value)
|
||||
if Heimdall_Data.config.macroer.debug then
|
||||
print(string.format("[%s] Stinkies changed, updating macro", ModuleName))
|
||||
end
|
||||
FixMacro(value)
|
||||
end)
|
||||
|
||||
print("Heimdall - Macroer loaded")
|
||||
if Heimdall_Data.config.macroer.debug then print(string.format("[%s] Module initialized", ModuleName)) end
|
||||
print("[Heimdall] Macroer loaded")
|
||||
end
|
||||
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Messenger"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Messenger = {}
|
||||
@@ -10,21 +10,12 @@ function shared.Messenger.Init()
|
||||
---@field channel string
|
||||
---@field data string
|
||||
|
||||
local function GetChannelId(channelName)
|
||||
local channels = { GetChannelList() }
|
||||
for i = 1, #channels, 2 do
|
||||
local id = channels[i]
|
||||
local name = channels[i + 1]
|
||||
if name == channelName then
|
||||
return id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function FindOrJoinChannel(channelName, password)
|
||||
local channelId = GetChannelName(channelName)
|
||||
if channelId == 0 then
|
||||
print("Channel", tostring(channelName), "not found, joining")
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Channel not found, joining: %s", ModuleName, channelName))
|
||||
end
|
||||
if password then
|
||||
JoinPermanentChannel(channelName, password)
|
||||
else
|
||||
@@ -32,6 +23,9 @@ function shared.Messenger.Init()
|
||||
end
|
||||
end
|
||||
channelId = GetChannelName(channelName)
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Channel found with ID: %s (%s)", ModuleName, channelId, channelName))
|
||||
end
|
||||
return channelId
|
||||
end
|
||||
|
||||
@@ -40,45 +34,143 @@ function shared.Messenger.Init()
|
||||
if not shared.messenger.queue then shared.messenger.queue = {} end
|
||||
if not shared.messenger.ticker then
|
||||
local function DoMessage()
|
||||
if not Heimdall_Data.config.messenger.enabled then return end
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Processing message queue - Size: %d", ModuleName, #shared.messenger.queue))
|
||||
end
|
||||
|
||||
if not Heimdall_Data.config.messenger.enabled then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Module disabled, skipping message processing", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
---@type Message
|
||||
local message = shared.messenger.queue[1]
|
||||
if not message then return end
|
||||
if not message.message or message.message == "" then return end
|
||||
if not message.channel or message.channel == "" then return end
|
||||
if not message then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Message queue empty", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Processing message - Channel: %s, Data: %s",
|
||||
ModuleName,
|
||||
message.channel or "nil",
|
||||
message.data or "nil"
|
||||
)
|
||||
)
|
||||
print(string.format("[%s] Message content: %s", ModuleName, message.message or "nil"))
|
||||
end
|
||||
|
||||
if not message.message or message.message == "" then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Invalid message: empty content", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if not message.channel or message.channel == "" then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Invalid message: no channel specified", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if string.find(message.channel, "^C") then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Converting channel type from C to CHANNEL", ModuleName))
|
||||
end
|
||||
message.channel = "CHANNEL"
|
||||
elseif string.find(message.channel, "^W") then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Converting channel type from W to WHISPER", ModuleName))
|
||||
end
|
||||
message.channel = "WHISPER"
|
||||
end
|
||||
|
||||
if message.channel == "CHANNEL" and message.data and string.match(message.data, "%D") then
|
||||
print("Channel presented as string:", message.data)
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Processing channel message: '%s' to '%s'",
|
||||
ModuleName,
|
||||
message.message,
|
||||
message.data
|
||||
)
|
||||
)
|
||||
end
|
||||
local channelId = GetChannelName(message.data)
|
||||
if channelId == 0 then
|
||||
print("Channel not found, joining")
|
||||
channelId = FindOrJoinChannel(message.data)
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Channel not found, attempting to join: %s", ModuleName, message.data))
|
||||
end
|
||||
channelId = FindOrJoinChannel(message.data)
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Channel join result - ID: %s", ModuleName, channelId))
|
||||
end
|
||||
end
|
||||
print("Channel resolved to id", channelId)
|
||||
message.data = tostring(channelId)
|
||||
end
|
||||
|
||||
table.remove(shared.messenger.queue, 1)
|
||||
if not message.message or message.message == "" then return end
|
||||
if not message.channel or message.channel == "" then return end
|
||||
if not message.data or message.data == "" then return end
|
||||
if not message.message or message.message == "" then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Skipping empty message", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if not message.channel or message.channel == "" then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Skipping message with no channel", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if not message.data or message.data == "" then
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Skipping message with no data", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Sending message: '%s' to %s:%s",
|
||||
ModuleName,
|
||||
message.message,
|
||||
message.channel,
|
||||
message.data
|
||||
)
|
||||
)
|
||||
end
|
||||
if string.len(message.message) > 255 then
|
||||
print(string.format("[%s] Message too long!!!!: %s", ModuleName, message.message))
|
||||
return
|
||||
end
|
||||
SendChatMessage(message.message, message.channel, nil, message.data)
|
||||
end
|
||||
local function Tick()
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(string.format("[%s] Tick - Queue size: %d", ModuleName, #shared.messenger.queue))
|
||||
end
|
||||
DoMessage()
|
||||
shared.messenger.ticker = C_Timer.NewTimer(Heimdall_Data.config.messenger.interval, Tick, 1)
|
||||
end
|
||||
Tick()
|
||||
end
|
||||
|
||||
--C_Timer.NewTicker(2, function()
|
||||
-- print("Q")
|
||||
-- table.insert(data.messenger.queue, {
|
||||
-- channel = "CHANNEL",
|
||||
-- data = "Foobar",
|
||||
-- message = "TEST"
|
||||
-- })
|
||||
--end)
|
||||
|
||||
print("Heimdall - Messenger loaded")
|
||||
if Heimdall_Data.config.messenger.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Module initialized with interval: %s",
|
||||
ModuleName,
|
||||
Heimdall_Data.config.messenger.interval
|
||||
)
|
||||
)
|
||||
end
|
||||
print("[Heimdall] Messenger loaded")
|
||||
end
|
||||
|
571
Modules/MinimapTagger.lua
Normal file
571
Modules/MinimapTagger.lua
Normal file
@@ -0,0 +1,571 @@
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
local ModuleName = "MinimapTagger"
|
||||
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)
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.MinimapTagger = {}
|
||||
function shared.MinimapTagger.Init()
|
||||
---@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.dumpTable(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
|
||||
|
||||
SlashCmdList["HEIMDALL_MINIMAPTAGGER"] = function(args) shared.MinimapTagger.Init() end
|
||||
SLASH_HEIMDALL_MINIMAPTAGGER1 = "/mf"
|
73
Modules/Network.lua
Normal file
73
Modules/Network.lua
Normal file
@@ -0,0 +1,73 @@
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
local ModuleName = "Network"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Network = {}
|
||||
function shared.Network.Init()
|
||||
if not shared.network then shared.network = {} end
|
||||
local updatePending = false
|
||||
|
||||
local function FriendListUpdate()
|
||||
updatePending = false
|
||||
if not Heimdall_Data.config.network.enabled then return end
|
||||
---@type table<string, boolean>
|
||||
local friends = {}
|
||||
for i = 1, GetNumFriends() do
|
||||
local name, _, _, _, connected, _, _, _ = GetFriendInfo(i)
|
||||
if name then
|
||||
friends[name] = connected
|
||||
if Heimdall_Data.config.network.debug then
|
||||
print(string.format("[%s] Friend %s is %s", ModuleName, name, connected and "online" or "offline"))
|
||||
end
|
||||
else
|
||||
if Heimdall_Data.config.network.debug then
|
||||
print(string.format("[%s] Friend %s is nil", ModuleName, i))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, member in ipairs(Heimdall_Data.config.network.members) do
|
||||
if friends[member] == nil and member ~= UnitName("player") then
|
||||
if Heimdall_Data.config.network.debug then
|
||||
print(string.format("[%s] Adding friend %s", ModuleName, member))
|
||||
end
|
||||
AddFriend(member)
|
||||
end
|
||||
end
|
||||
friends[UnitName("player")] = true
|
||||
|
||||
shared.networkNodes = {}
|
||||
-- Why are we skipping this again...?
|
||||
-- if false then shared.networkNodes[#shared.networkNodes + 1] = UnitName("player") end
|
||||
for _, player in ipairs(Heimdall_Data.config.network.members) do
|
||||
if friends[player] then
|
||||
shared.networkNodes[#shared.networkNodes + 1] = player
|
||||
if Heimdall_Data.config.network.debug then
|
||||
print(string.format("[%s] Adding network node %s", ModuleName, player))
|
||||
end
|
||||
end
|
||||
end
|
||||
if Heimdall_Data.config.network.debug then
|
||||
print(string.format("[%s] Network nodes:", ModuleName))
|
||||
shared.dumpTable(shared.networkNodes)
|
||||
end
|
||||
end
|
||||
|
||||
local friendsFrame = CreateFrame("Frame")
|
||||
friendsFrame:RegisterEvent("FRIENDLIST_UPDATE")
|
||||
friendsFrame:SetScript("OnEvent", function(self, event, ...) end)
|
||||
|
||||
local function NetworkTick()
|
||||
if Heimdall_Data.config.network.debug then print("Network module is updating.") end
|
||||
ShowFriends()
|
||||
updatePending = true
|
||||
C_Timer.After(1, function()
|
||||
if updatePending then FriendListUpdate() end
|
||||
end)
|
||||
shared.network.ticker = C_Timer.NewTimer(Heimdall_Data.config.network.updateInterval, NetworkTick, 1)
|
||||
end
|
||||
|
||||
NetworkTick()
|
||||
print("[Heimdall] Network module loaded")
|
||||
end
|
183
Modules/NetworkMessenger.lua
Normal file
183
Modules/NetworkMessenger.lua
Normal file
@@ -0,0 +1,183 @@
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
local ModuleName = "NetworkMessenger"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.NetworkMessenger = {}
|
||||
function shared.NetworkMessenger.Init()
|
||||
RegisterAddonMessagePrefix(Heimdall_Data.config.addonPrefix)
|
||||
|
||||
if not shared.networkMessenger then shared.networkMessenger = {} end
|
||||
if not shared.networkMessenger.queue then shared.networkMessenger.queue = {} end
|
||||
if not shared.networkMessenger.ticker then
|
||||
local function DoMessage()
|
||||
--if Heimdall_Data.config.networkMessenger.debug then
|
||||
-- print(string.format("[%s] Processing network message queue", ModuleName))
|
||||
--end
|
||||
if not Heimdall_Data.config.networkMessenger.enabled then
|
||||
--if Heimdall_Data.config.networkMessenger.debug then
|
||||
-- print(string.format("[%s] Module disabled, skipping network message processing", ModuleName))
|
||||
--end
|
||||
return
|
||||
end
|
||||
---@type Message
|
||||
local message = shared.networkMessenger.queue[1]
|
||||
if not message then
|
||||
--if Heimdall_Data.config.networkMessenger.debug then
|
||||
-- print(string.format("[%s] Network message queue empty", ModuleName))
|
||||
--end
|
||||
return
|
||||
end
|
||||
if not message.message or message.message == "" then
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Invalid network message: empty content", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if not message.channel or message.channel == "" then
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Invalid network message: no channel specified", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
table.remove(shared.networkMessenger.queue, 1)
|
||||
if not message.message or message.message == "" then
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Skipping empty network message", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if not message.channel or message.channel == "" then
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Skipping network message with no channel", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if not message.data or message.data == "" then
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Skipping network message with no data", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Sending network message: '%s' to %s:%s",
|
||||
ModuleName,
|
||||
message.message,
|
||||
message.channel,
|
||||
message.data
|
||||
)
|
||||
)
|
||||
end
|
||||
local payload = string.format("dmessage|%s|%s|%s", message.message, message.channel, message.data)
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Payload: %s", ModuleName, payload))
|
||||
end
|
||||
if not shared.networkNodes or #shared.networkNodes == 0 then
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] No network nodes found, wtf????", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
local target = shared.networkNodes[1]
|
||||
SendAddonMessage(Heimdall_Data.config.addonPrefix, payload, "WHISPER", target)
|
||||
end
|
||||
local function Tick()
|
||||
--if Heimdall_Data.config.networkMessenger.debug then
|
||||
-- local queueSize = #shared.networkMessenger.queue
|
||||
-- print(string.format("[%s] Queue check - Network messages pending: %d", ModuleName, queueSize))
|
||||
--end
|
||||
DoMessage()
|
||||
shared.networkMessenger.ticker = C_Timer.NewTimer(Heimdall_Data.config.networkMessenger.interval, Tick, 1)
|
||||
end
|
||||
Tick()
|
||||
end
|
||||
|
||||
-- If we are the leader then we delegate messages (dmessage)
|
||||
-- If we get a "message" command from leader then we send the message
|
||||
|
||||
local nextIdx = 1
|
||||
local addonMsgFrame = CreateFrame("Frame")
|
||||
addonMsgFrame:RegisterEvent("CHAT_MSG_ADDON")
|
||||
addonMsgFrame:SetScript("OnEvent", function(self, event, prefix, message, channel, source)
|
||||
if not Heimdall_Data.config.networkMessenger.enabled then return end
|
||||
if prefix ~= Heimdall_Data.config.addonPrefix then return end
|
||||
source = string.match(source, "[^%-]+")
|
||||
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Received message from %s: %s", ModuleName, source, message))
|
||||
end
|
||||
if #shared.networkNodes == 0 then
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] No network nodes found, wtf????", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- There should always be at least one network node ergo should always exist a leader
|
||||
-- Because the us, the player, is also a node
|
||||
--local networkLeader = shared.networkNodes[1]
|
||||
--if source ~= networkLeader then
|
||||
-- if Heimdall_Data.config.networkMessenger.debug then
|
||||
-- print(string.format("[%s] Message from %s is not from the network leader (%s)", ModuleName, source,
|
||||
-- networkLeader))
|
||||
-- end
|
||||
-- return
|
||||
--end
|
||||
|
||||
local parts = shared.Split(message, "|")
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Received message parts:", ModuleName))
|
||||
shared.dumpTable(parts)
|
||||
end
|
||||
local command = strtrim(parts[1])
|
||||
if command == "message" then
|
||||
local content = strtrim(tostring(parts[2]))
|
||||
local targetchannel = strtrim(tostring(parts[3]))
|
||||
local target = strtrim(tostring(parts[4]))
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(
|
||||
string.format("[%s] Received message command: %s %s %s", ModuleName, content, targetchannel, target)
|
||||
)
|
||||
end
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = targetchannel,
|
||||
message = content,
|
||||
data = target,
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
elseif command == "dmessage" then
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Received dmessage command", ModuleName))
|
||||
end
|
||||
parts[1] = "message"
|
||||
local content = table.concat(parts, "|")
|
||||
|
||||
if nextIdx > #shared.networkNodes then nextIdx = 1 end
|
||||
local recipient = shared.networkNodes[nextIdx]
|
||||
nextIdx = nextIdx + 1
|
||||
if Heimdall_Data.config.networkMessenger.debug then
|
||||
print(string.format("[%s] Sending message %s to %s", ModuleName, content, recipient))
|
||||
end
|
||||
SendAddonMessage(Heimdall_Data.config.addonPrefix, content, "WHISPER", recipient)
|
||||
end
|
||||
end)
|
||||
|
||||
--/run Heimdall_Data.Test()
|
||||
Heimdall_Data.Test = function()
|
||||
local testmsg = {
|
||||
channel = "W",
|
||||
message = "Hi, mom!",
|
||||
data = "Secundus",
|
||||
}
|
||||
for i = 1, 36 do
|
||||
table.insert(shared.networkMessenger.queue, testmsg)
|
||||
end
|
||||
end
|
||||
|
||||
print("[Heimdall] NetworkMessenger module loaded")
|
||||
end
|
295
Modules/Noter.lua
Normal file
295
Modules/Noter.lua
Normal file
@@ -0,0 +1,295 @@
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
local ModuleName = "Noter"
|
||||
|
||||
---@class Note
|
||||
---@field source string
|
||||
---@field for string
|
||||
---@field date string
|
||||
---@field note string
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Noter = {}
|
||||
function shared.Noter.Init()
|
||||
-- ---Hopefully this will not be necessary
|
||||
-- ---@param text string
|
||||
-- ---@param size number
|
||||
-- ---@return string[]
|
||||
-- local function Partition(text, size)
|
||||
-- local words = {}
|
||||
-- for word in text:gmatch("[^,]+") do
|
||||
-- words[#words + 1] = word
|
||||
-- end
|
||||
|
||||
-- local ret = {}
|
||||
-- local currentChunk = ""
|
||||
|
||||
-- for _, word in ipairs(words) do
|
||||
-- if #currentChunk + #word + 1 <= size then
|
||||
-- currentChunk = currentChunk .. (currentChunk == "" and word or " " .. word)
|
||||
-- else
|
||||
-- if #currentChunk > 0 then ret[#ret + 1] = currentChunk end
|
||||
-- currentChunk = word
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- if #currentChunk > 0 then ret[#ret + 1] = currentChunk end
|
||||
|
||||
-- return ret
|
||||
-- end
|
||||
---@param array any[]
|
||||
---@return any[]
|
||||
local function Compact(array)
|
||||
local compacted = {}
|
||||
for _, v in pairs(array) do
|
||||
compacted[#compacted + 1] = v
|
||||
end
|
||||
return compacted
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@param args string[]
|
||||
local function DeleteNotes(name, args)
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Delete note command received for: %s", ModuleName, name))
|
||||
end
|
||||
local range = args[4]
|
||||
if range then
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Range received for delete note: %s", ModuleName, range))
|
||||
end
|
||||
local indices = shared.Split(range, "..")
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Indices for range deletion: %s", ModuleName, table.concat(indices, ", ")))
|
||||
shared.dumpTable(indices)
|
||||
end
|
||||
local start = tonumber(indices[1])
|
||||
local finish = tonumber(indices[2])
|
||||
|
||||
if not start then
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Invalid start range for delete note: %s", ModuleName, tostring(start)))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if not finish then finish = start end
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Deleting note range %s to %s for: %s", ModuleName, start, finish, name))
|
||||
end
|
||||
|
||||
-- Here, because we are deleting random notes, we lose the "iterative" index property
|
||||
-- Ie it's not longer 1..100, it might be 1..47, 50, 68..100
|
||||
-- Which means that we cannot use ipairs, bad!
|
||||
for i = start, finish do
|
||||
if not Heimdall_Data.config.notes[name] then Heimdall_Data.config.notes[name] = {} end
|
||||
if not Heimdall_Data.config.notes[name][i] then
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Note at index %s does not exist", ModuleName, i))
|
||||
end
|
||||
else
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Deleting note %s at index %s", ModuleName, name, i))
|
||||
shared.dumpTable(Heimdall_Data.config.notes[name][i])
|
||||
end
|
||||
Heimdall_Data.config.notes[name][i] = nil
|
||||
end
|
||||
end
|
||||
Heimdall_Data.config.notes[name] = Compact(Heimdall_Data.config.notes[name])
|
||||
end
|
||||
end
|
||||
|
||||
---@param channel string
|
||||
---@param index number
|
||||
---@param note Note
|
||||
local function PrintNote(channel, index, note)
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Printing note at index %d for: %s", ModuleName, index, note.source))
|
||||
print(string.format("[%s] [%s][%d] %s: %s", ModuleName, note.source, index, note.date, note.note))
|
||||
end
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = string.format("[%s][%d] %s: %s", note.source, index, note.date, note.note),
|
||||
}
|
||||
--table.insert(shared.messenger.queue, msg)
|
||||
table.insert(shared.networkMessenger.queue, msg)
|
||||
end
|
||||
---@param name string
|
||||
---@param args string[]
|
||||
local function PrintNotes(channel, name, args)
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Print note command received for: %s", ModuleName, name))
|
||||
end
|
||||
local range = args[3]
|
||||
if not range then
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] No range specified for print note, defaulting to last %d notes",
|
||||
ModuleName,
|
||||
Heimdall_Data.config.noter.lastNotes
|
||||
)
|
||||
)
|
||||
end
|
||||
local notes = Heimdall_Data.config.notes[name] or {}
|
||||
local start = math.max(1, #notes - Heimdall_Data.config.noter.lastNotes + 1)
|
||||
local finish = #notes
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Printing notes from %d to %d for: %s", ModuleName, start, finish, name))
|
||||
end
|
||||
for i = start, finish do
|
||||
PrintNote(channel, i, notes[i])
|
||||
end
|
||||
return
|
||||
end
|
||||
if range then
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Range received for print note: %s", ModuleName, range))
|
||||
end
|
||||
local indices = shared.Split(range, "..")
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Indices for range printing: %s", ModuleName, table.concat(indices, ", ")))
|
||||
shared.dumpTable(indices)
|
||||
end
|
||||
local start = tonumber(indices[1])
|
||||
local finish = tonumber(indices[2])
|
||||
|
||||
if not start then
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Invalid start range for print note: %s", ModuleName, tostring(start)))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if not finish then finish = start end
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Printing note range %s to %s for: %s", ModuleName, start, finish, name))
|
||||
end
|
||||
|
||||
for i = start, finish do
|
||||
if not Heimdall_Data.config.notes[name] then Heimdall_Data.config.notes[name] = {} end
|
||||
if not Heimdall_Data.config.notes[name][i] then
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Note at index %s does not exist", ModuleName, i))
|
||||
end
|
||||
else
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Printing note %s at index %s", ModuleName, name, i))
|
||||
shared.dumpTable(Heimdall_Data.config.notes[name][i])
|
||||
end
|
||||
PrintNote(channel, i, Heimdall_Data.config.notes[name][i])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@param sender string
|
||||
---@param args string[]
|
||||
local function AddNote(name, sender, args)
|
||||
if not Heimdall_Data.config.notes[name] then Heimdall_Data.config.notes[name] = {} end
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Adding note for: %s from: %s", ModuleName, name, sender))
|
||||
shared.dumpTable(args)
|
||||
end
|
||||
local msgparts = {}
|
||||
for i = 3, #args do
|
||||
msgparts[#msgparts + 1] = args[i]
|
||||
end
|
||||
local msg = table.concat(msgparts, " ")
|
||||
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Adding note for: %s from: %s", ModuleName, name, sender))
|
||||
print(string.format("[%s] Note: %s", ModuleName, msg))
|
||||
end
|
||||
|
||||
local note = {
|
||||
source = sender,
|
||||
date = date("%Y-%m-%dT%H:%M:%S"),
|
||||
note = msg,
|
||||
}
|
||||
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Adding note", ModuleName))
|
||||
shared.dumpTable(note)
|
||||
end
|
||||
table.insert(Heimdall_Data.config.notes[name], note)
|
||||
end
|
||||
|
||||
-- Here's the plan:
|
||||
-- Implement a "note" command, that will do everything
|
||||
-- Saying "note <name> <note>" will add a note to the list for the character
|
||||
-- Saying "note <name>" will list last N notes
|
||||
-- Saying "note <name> i" will list the i-th note
|
||||
-- Saying "note <name> i..j" will list notes from i to j
|
||||
-- Saying "note <name> delete i" will delete the i-th note
|
||||
-- Saying "note <name> delete i..j" will delete notes from i to j
|
||||
local noterChannelFrame = CreateFrame("Frame")
|
||||
noterChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL")
|
||||
noterChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
|
||||
--if Heimdall_Data.config.noter.debug then
|
||||
-- print(string.format("[%s] Event received", ModuleName))
|
||||
-- shared.dumpTable(Heimdall_Data.config.noter)
|
||||
--end
|
||||
if not Heimdall_Data.config.noter.enabled then
|
||||
--if Heimdall_Data.config.noter.debug then
|
||||
-- print(string.format("[%s] Module disabled, ignoring event", ModuleName))
|
||||
--end
|
||||
return
|
||||
end
|
||||
local channelId = select(6, ...)
|
||||
local _, channelname = GetChannelName(channelId)
|
||||
local ok = false
|
||||
for _, channel in pairs(Heimdall_Data.config.noter.channels) do
|
||||
if channelname == channel then
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not ok then
|
||||
--if Heimdall_Data.config.noter.debug then
|
||||
-- print(string.format("[%s] Channel %s does not match the master channel %s", ModuleName, channelname, Heimdall_Data.config.noter.masterChannel))
|
||||
--end
|
||||
return
|
||||
end
|
||||
|
||||
sender = string.match(sender, "^[^-]+")
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Message from: %s", ModuleName, sender))
|
||||
shared.dumpTable(Heimdall_Data.config.noter)
|
||||
end
|
||||
|
||||
if not msg or msg == "" then
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Empty message, ignoring", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local args = { strsplit(" ", msg) }
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Arguments received: %s", ModuleName, table.concat(args, ", ")))
|
||||
shared.dumpTable(args)
|
||||
end
|
||||
local command = args[1]
|
||||
if command == "note" then
|
||||
local name = strtrim(string.lower(args[2] or ""))
|
||||
if Heimdall_Data.config.noter.debug then
|
||||
print(string.format("[%s] Note command received for: %s", ModuleName, name))
|
||||
end
|
||||
local note = strtrim(args[3] or "")
|
||||
if Heimdall_Data.config.noter.debug then print(string.format("[%s] Note: %s", ModuleName, note)) end
|
||||
if note == "delete" then
|
||||
DeleteNotes(name, args)
|
||||
elseif string.find(note, "^[%d%.]*$") then
|
||||
PrintNotes(channelname, name, args)
|
||||
else
|
||||
AddNote(name, sender, args)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
print("[Heimdall] Commander module loaded")
|
||||
end
|
@@ -8,12 +8,8 @@ local function Init()
|
||||
if otherType == "table" and other._type and other._type == self._type and other._value then
|
||||
return self._value + other._value
|
||||
end
|
||||
if otherType == "string" and self._type == otherType then
|
||||
return self._value .. other
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then
|
||||
return self._value + other
|
||||
end
|
||||
if otherType == "string" and self._type == otherType then return self._value .. other end
|
||||
if otherType == "number" and self._type == otherType then return self._value + other end
|
||||
return nil
|
||||
end,
|
||||
---@param self ReactiveValue
|
||||
@@ -24,9 +20,7 @@ local function Init()
|
||||
if otherType == "table" and other._type and other._type == self._type and other._value then
|
||||
return self._value * other._value
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then
|
||||
return self._value * other
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then return self._value * other end
|
||||
return nil
|
||||
end,
|
||||
---@param self ReactiveValue
|
||||
@@ -37,9 +31,7 @@ local function Init()
|
||||
if otherType == "table" and other._type and other._type == self._type and other._value then
|
||||
return self._value - other._value
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then
|
||||
return self._value - other
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then return self._value - other end
|
||||
return nil
|
||||
end,
|
||||
---@param self ReactiveValue
|
||||
@@ -50,9 +42,7 @@ local function Init()
|
||||
if otherType == "table" and other._type and other._type == self._type and other._value then
|
||||
return self._value / other._value
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then
|
||||
return self._value / other
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then return self._value / other end
|
||||
return nil
|
||||
end,
|
||||
---@param self ReactiveValue
|
||||
@@ -63,9 +53,7 @@ local function Init()
|
||||
if otherType == "table" and other._type and other._type == self._type and other._value then
|
||||
return self._value % other._value
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then
|
||||
return self._value % other
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then return self._value % other end
|
||||
return nil
|
||||
end,
|
||||
---@param self ReactiveValue
|
||||
@@ -76,9 +64,7 @@ local function Init()
|
||||
if otherType == "table" and other._type and other._type == self._type and other._value then
|
||||
return self._value ^ other._value
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then
|
||||
return self._value ^ other
|
||||
end
|
||||
if otherType == "number" and self._type == otherType then return self._value ^ other end
|
||||
return nil
|
||||
end,
|
||||
---@param self ReactiveValue
|
||||
@@ -134,19 +120,13 @@ local function Init()
|
||||
---@param self ReactiveValue
|
||||
---@return number
|
||||
__len = function(self)
|
||||
if self._type == "table" then
|
||||
return #self._value
|
||||
end
|
||||
if self._type == "string" then
|
||||
return string.len(self._value)
|
||||
end
|
||||
if self._type == "table" then return #self._value end
|
||||
if self._type == "string" then return string.len(self._value) end
|
||||
return 0
|
||||
end,
|
||||
---@param self ReactiveValue
|
||||
---@return string
|
||||
__tostring = function(self)
|
||||
return tostring(self._value)
|
||||
end,
|
||||
__tostring = function(self) return tostring(self._value) end,
|
||||
---@param self ReactiveValue
|
||||
---@param key string
|
||||
---@param value any
|
||||
@@ -168,9 +148,7 @@ local function Init()
|
||||
-- If the value being assigned is a ReactiveValue
|
||||
-- Then listen to changes on it as well
|
||||
-- And propagate those changes upwards
|
||||
if self._recursive and getmetatable(value) == getmetatable(self) then
|
||||
self:_setupListeners(key, value)
|
||||
end
|
||||
if self._recursive and getmetatable(value) == getmetatable(self) then self:_setupListeners(key, value) end
|
||||
|
||||
self:_notify()
|
||||
self:_notifyFieldChanged(ChangedKey)
|
||||
@@ -181,18 +159,12 @@ local function Init()
|
||||
---@return any|nil
|
||||
__index = function(self, key)
|
||||
local value = rawget(self, key)
|
||||
if value ~= nil then
|
||||
return value
|
||||
end
|
||||
if rawget(self, "_type") ~= "table" then
|
||||
return nil
|
||||
end
|
||||
if value ~= nil then return value end
|
||||
if rawget(self, "_type") ~= "table" then return nil end
|
||||
local innerTable = rawget(self, "_value")
|
||||
if innerTable ~= nil then
|
||||
return rawget(innerTable, key)
|
||||
end
|
||||
if innerTable ~= nil then return rawget(innerTable, key) end
|
||||
return nil
|
||||
end
|
||||
end,
|
||||
-- __index = ReactiveValue
|
||||
}
|
||||
|
||||
@@ -343,14 +315,10 @@ local function Init()
|
||||
self._recursive = recursive or false
|
||||
|
||||
---@return any
|
||||
self.get = function(self)
|
||||
return self._value
|
||||
end
|
||||
self.get = function(self) return self._value end
|
||||
---@param newValue any
|
||||
self.set = function(self, newValue)
|
||||
if self._value == newValue then
|
||||
return
|
||||
end
|
||||
if self._value == newValue then return end
|
||||
if type(newValue) ~= self._type then
|
||||
error("Expected " .. self._type .. ", got " .. type(newValue))
|
||||
return
|
||||
@@ -364,22 +332,16 @@ local function Init()
|
||||
return function() end
|
||||
end
|
||||
self._listeners[callback] = true
|
||||
return function()
|
||||
self._listeners[callback] = nil
|
||||
end
|
||||
return function() self._listeners[callback] = nil end
|
||||
end
|
||||
self.onFieldChange = function(self, field, callback)
|
||||
if type(callback) ~= "function" then
|
||||
error("Expected function, got " .. type(callback))
|
||||
return function() end
|
||||
end
|
||||
if self._fieldListeners[field] == nil then
|
||||
self._fieldListeners[field] = {}
|
||||
end
|
||||
if self._fieldListeners[field] == nil then self._fieldListeners[field] = {} end
|
||||
self._fieldListeners[field][callback] = true
|
||||
return function()
|
||||
self._fieldListeners[field][callback] = nil
|
||||
end
|
||||
return function() self._fieldListeners[field][callback] = nil end
|
||||
end
|
||||
self.onAnyFieldChange = function(self, callback, depth)
|
||||
depth = depth or 99999
|
||||
@@ -387,13 +349,9 @@ local function Init()
|
||||
error("Expected function, got " .. type(callback))
|
||||
return function() end
|
||||
end
|
||||
if self._anyFieldListeners[depth] == nil then
|
||||
self._anyFieldListeners[depth] = {}
|
||||
end
|
||||
if self._anyFieldListeners[depth] == nil then self._anyFieldListeners[depth] = {} end
|
||||
self._anyFieldListeners[depth][callback] = true
|
||||
return function()
|
||||
self._anyFieldListeners[depth][callback] = nil
|
||||
end
|
||||
return function() self._anyFieldListeners[depth][callback] = nil end
|
||||
end
|
||||
self.once = function(self, callback)
|
||||
if type(callback) ~= "function" then
|
||||
@@ -401,15 +359,11 @@ local function Init()
|
||||
return function() end
|
||||
end
|
||||
self._oneTimeListeners[callback] = true
|
||||
return function()
|
||||
self._oneTimeListeners[callback] = nil
|
||||
end
|
||||
return function() self._oneTimeListeners[callback] = nil end
|
||||
end
|
||||
|
||||
self._setupAllListenersRecursively = function(self)
|
||||
if self._type ~= "table" then
|
||||
return
|
||||
end
|
||||
if self._type ~= "table" then return end
|
||||
for key, value in pairs(self._value) do
|
||||
self:_setupListeners(key, value, true)
|
||||
end
|
||||
@@ -419,12 +373,8 @@ local function Init()
|
||||
---@param recursive boolean?
|
||||
self._setupListeners = function(self, key, value, recursive)
|
||||
recursive = recursive or false
|
||||
if self._type ~= "table" then
|
||||
return
|
||||
end
|
||||
if getmetatable(value) ~= getmetatable(self) then
|
||||
return
|
||||
end
|
||||
if self._type ~= "table" then return end
|
||||
if getmetatable(value) ~= getmetatable(self) then return end
|
||||
value._recursive = true
|
||||
if value._type == "table" then
|
||||
value:onAnyFieldChange(function(key2)
|
||||
@@ -440,14 +390,10 @@ local function Init()
|
||||
end)
|
||||
end
|
||||
|
||||
if recursive then
|
||||
value:_setupAllListenersRecursively()
|
||||
end
|
||||
if recursive then value:_setupAllListenersRecursively() end
|
||||
end
|
||||
|
||||
if recursive then
|
||||
self:_setupAllListenersRecursively()
|
||||
end
|
||||
if recursive then self:_setupAllListenersRecursively() end
|
||||
|
||||
self._notify = function(self)
|
||||
for listener, _ in pairs(self._oneTimeListeners) do
|
||||
@@ -474,9 +420,7 @@ local function Init()
|
||||
end
|
||||
|
||||
local strfield = table.concat(field, ".")
|
||||
if self._fieldListeners[strfield] == nil then
|
||||
return
|
||||
end
|
||||
if self._fieldListeners[strfield] == nil then return end
|
||||
for listener, _ in pairs(self._fieldListeners[strfield]) do
|
||||
-- task.spawn(listener, value, type(value))
|
||||
listener(value, type(value))
|
||||
@@ -661,7 +605,5 @@ local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("PLAYER_LOGIN")
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
frame:RegisterEvent("GUILD_ROSTER_UPDATE")
|
||||
frame:SetScript("OnEvent", function(self, event, ...)
|
||||
Init()
|
||||
end)
|
||||
frame:SetScript("OnEvent", function(self, event, ...) Init() end)
|
||||
Init()
|
||||
|
83
Modules/Sniffer.lua
Normal file
83
Modules/Sniffer.lua
Normal file
@@ -0,0 +1,83 @@
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
local ModuleName = "Sniffer"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Sniffer = {}
|
||||
function shared.Sniffer.Init()
|
||||
if Heimdall_Data.config.sniffer.debug then print(string.format("[%s] Module initializing", ModuleName)) end
|
||||
local smellThrottle = {}
|
||||
local SmellStinky = function(stinky)
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("%s: SmellStinky", ModuleName))
|
||||
shared.dumpTable(Heimdall_Data.config.sniffer)
|
||||
end
|
||||
if not Heimdall_Data.config.sniffer.enabled then return end
|
||||
if Heimdall_Data.config.sniffer.stinky and not shared.IsStinky(stinky) then
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("%s: Stinky not found in config", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
if smellThrottle[stinky] and GetTime() - smellThrottle[stinky] < Heimdall_Data.config.sniffer.throttleTime then
|
||||
if Heimdall_Data.config.sniffer.debug then print(string.format("%s: Throttled", ModuleName)) end
|
||||
return
|
||||
end
|
||||
smellThrottle[stinky] = GetTime()
|
||||
|
||||
for _, channel in pairs(Heimdall_Data.config.sniffer.channels) do
|
||||
local locale = shared.GetLocaleForChannel(channel)
|
||||
local text = string.format(shared._L("snifferStinky", locale), stinky)
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text,
|
||||
}
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("[%s] Queuing sniffer message", ModuleName))
|
||||
shared.dumpTable(msg)
|
||||
end
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
end
|
||||
end
|
||||
|
||||
local cleuFrame = CreateFrame("Frame")
|
||||
cleuFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
|
||||
cleuFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("[%s] Received event: %s", ModuleName, event))
|
||||
end
|
||||
if not Heimdall_Data.config.sniffer.enabled then
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring event", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
local source, destination, err
|
||||
source, err = CLEUParser.GetSourceName(...)
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("[%s] Processing source: %s", ModuleName, source))
|
||||
end
|
||||
if err then
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("[%s] Error parsing source: %s", ModuleName, err))
|
||||
end
|
||||
return
|
||||
end
|
||||
SmellStinky(source)
|
||||
destination, err = CLEUParser.GetDestName(...)
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("[%s] Processing destination: %s", ModuleName, destination))
|
||||
end
|
||||
if err then
|
||||
if Heimdall_Data.config.sniffer.debug then
|
||||
print(string.format("[%s] Error parsing destination: %s", ModuleName, err))
|
||||
end
|
||||
return
|
||||
end
|
||||
SmellStinky(destination)
|
||||
end)
|
||||
if Heimdall_Data.config.sniffer.debug then print(string.format("[%s] Module initialized", ModuleName)) end
|
||||
print("[Heimdall] Sniffer loaded")
|
||||
end
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Spotter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Spotter = {}
|
||||
@@ -27,15 +27,52 @@ function shared.Spotter.Init()
|
||||
---@return boolean
|
||||
---@return string? error
|
||||
local function ShouldNotify(unit, name, faction, hostile)
|
||||
if Heimdall_Data.config.agents[name] then return false end
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Checking notification criteria for %s (%s)", ModuleName, name, faction))
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.agents[name] then
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Skipping agent: %s", ModuleName, name))
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.spotter.stinky then
|
||||
if Heimdall_Data.config.stinkies[name] then return true end
|
||||
if shared.IsStinky(name) then
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Notifying - Found stinky: %s", ModuleName, name))
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.spotter.alliance then
|
||||
if faction == "Alliance" then return true end
|
||||
if faction == "Alliance" then
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Notifying - Found Alliance player: %s", ModuleName, name))
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.spotter.hostile then
|
||||
if hostile then return true end
|
||||
if hostile then
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Notifying - Found hostile player: %s", ModuleName, name))
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Using everyone setting: %s",
|
||||
ModuleName,
|
||||
tostring(Heimdall_Data.config.spotter.everyone)
|
||||
)
|
||||
)
|
||||
end
|
||||
return Heimdall_Data.config.spotter.everyone
|
||||
end
|
||||
@@ -43,14 +80,30 @@ function shared.Spotter.Init()
|
||||
---@param unit string
|
||||
---@return string?
|
||||
local function NotifySpotted(unit)
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Processing spotted unit: %s", ModuleName, unit))
|
||||
end
|
||||
|
||||
if not unit then return string.format("Could not find unit %s", tostring(unit)) end
|
||||
if not UnitIsPlayer(unit) then return nil end
|
||||
if not UnitIsPlayer(unit) then
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Ignoring non-player unit: %s", ModuleName, unit))
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local name = UnitName(unit)
|
||||
if not name then return string.format("Could not find name for unit %s", tostring(unit)) end
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Processing player: %s", ModuleName, name))
|
||||
end
|
||||
|
||||
local time = GetTime()
|
||||
if throttleTable[name] and time - throttleTable[name] < Heimdall_Data.config.spotter.throttleTime then
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
local remainingTime = Heimdall_Data.config.spotter.throttleTime - (time - throttleTable[name])
|
||||
print(string.format("[%s] Player %s throttled for %.1f more seconds", ModuleName, name, remainingTime))
|
||||
end
|
||||
return string.format("Throttled %s", tostring(name))
|
||||
end
|
||||
throttleTable[name] = time
|
||||
@@ -59,66 +112,113 @@ function shared.Spotter.Init()
|
||||
if not race then return string.format("Could not find race for unit %s", tostring(unit)) end
|
||||
local faction = shared.raceMap[race]
|
||||
if not faction then return string.format("Could not find faction for race %s", tostring(race)) end
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Player %s is %s (%s)", ModuleName, name, race, faction))
|
||||
end
|
||||
|
||||
local hostile = UnitCanAttack("player", unit)
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Player %s is %s", ModuleName, name, hostile and "hostile" or "friendly"))
|
||||
end
|
||||
|
||||
local doNotify = ShouldNotify(unit, name, faction, hostile)
|
||||
if not doNotify then return string.format("Not notifying for %s", tostring(name)) end
|
||||
if not doNotify then
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Skipping notification for %s", ModuleName, name))
|
||||
end
|
||||
return string.format("Not notifying for %s", tostring(name))
|
||||
end
|
||||
|
||||
local hp = UnitHealth(unit)
|
||||
if not hp then return string.format("Could not find hp for unit %s", tostring(unit)) end
|
||||
|
||||
local maxHp = UnitHealthMax(unit)
|
||||
if not maxHp then return string.format("Could not find maxHp for unit %s", tostring(unit)) end
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Player %s health: %s/%s", ModuleName, name, FormatHP(hp), FormatHP(maxHp)))
|
||||
end
|
||||
|
||||
local class = UnitClass(unit)
|
||||
if not class then return string.format("Could not find class for unit %s", tostring(unit)) end
|
||||
|
||||
local location = Heimdall_Data.config.spotter.zoneOverride
|
||||
if not location or location == "" then
|
||||
local zone = GetZoneText()
|
||||
if not zone then return string.format("Could not find zone for unit %s", tostring(unit)) end
|
||||
local subzone = GetSubZoneText()
|
||||
if not subzone then subzone = "" end
|
||||
location = string.format("%s (%s)", zone, subzone)
|
||||
local zone, subzone = GetZoneText() or "Unknown", GetSubZoneText() or "Unknown"
|
||||
if Heimdall_Data.config.spotter.zoneOverride then
|
||||
zone = Heimdall_Data.config.spotter.zoneOverride or ""
|
||||
subzone = ""
|
||||
end
|
||||
|
||||
local x, y = GetPlayerMapPosition("player")
|
||||
local stinky = Heimdall_Data.config.stinkies[name] or false
|
||||
local text = string.format("I see (%s) %s/%s %s of race %s (%s) with health %s/%s at %s (%2.2f, %2.2f)",
|
||||
hostile and "Hostile" or "Friendly",
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Player %s coordinates: %.2f, %.2f", ModuleName, name, x * 100, y * 100))
|
||||
end
|
||||
|
||||
local pvpOn = UnitIsPVP(unit)
|
||||
local stinky = shared.IsStinky(name) or false
|
||||
SetMapToCurrentZone()
|
||||
SetMapByID(GetCurrentMapAreaID())
|
||||
local areaId = tostring(GetCurrentMapAreaID())
|
||||
|
||||
for _, channel in pairs(Heimdall_Data.config.spotter.channels) do
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Processing channel: %s", ModuleName, channel))
|
||||
end
|
||||
local locale = shared.GetLocaleForChannel(channel)
|
||||
local text = string.format(
|
||||
shared._L("spotterSpotted", locale),
|
||||
hostile and shared._L("hostile", locale) or shared._L("friendly", locale),
|
||||
name,
|
||||
class,
|
||||
shared._L(class, locale),
|
||||
stinky and string.format("(%s)", "!!!!") or "",
|
||||
race,
|
||||
faction,
|
||||
FormatHP(hp),
|
||||
FormatHP(maxHp),
|
||||
location,
|
||||
x * 100, y * 100)
|
||||
shared._L(race, locale),
|
||||
shared._L(faction, locale),
|
||||
pvpOn and shared._L("pvpOn", locale) or shared._L("pvpOff", locale),
|
||||
string.gsub(FormatHP(hp), "M", "kk"),
|
||||
string.gsub(FormatHP(maxHp), "M", "kk"),
|
||||
shared._L(zone, locale),
|
||||
shared._L(subzone, locale),
|
||||
areaId,
|
||||
x * 100,
|
||||
y * 100
|
||||
)
|
||||
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.spotter.notifyChannel,
|
||||
message = text
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text,
|
||||
}
|
||||
--shared.dumpTable(msg)
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Queuing spotter message", ModuleName))
|
||||
shared.dumpTable(msg)
|
||||
end
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
end
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("NAME_PLATE_UNIT_ADDED")
|
||||
frame:RegisterEvent("UNIT_TARGET")
|
||||
frame:SetScript("OnEvent", function(self, event, unit)
|
||||
if not Heimdall_Data.config.spotter.enabled then return end
|
||||
if event == "UNIT_TARGET" then
|
||||
unit = "target"
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Event received: %s for unit: %s", ModuleName, event, unit or "target"))
|
||||
end
|
||||
|
||||
if not Heimdall_Data.config.spotter.enabled then
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring event", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == "UNIT_TARGET" then unit = "target" end
|
||||
|
||||
local err = NotifySpotted(unit)
|
||||
if err then
|
||||
print(string.format("Error notifying %s: %s", tostring(unit), tostring(err)))
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Error processing unit %s: %s", ModuleName, unit, err))
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - Spotter loaded")
|
||||
if Heimdall_Data.config.spotter.debug then print(string.format("[%s] Module initialized", ModuleName)) end
|
||||
print("[Heimdall] Spotter loaded")
|
||||
end
|
||||
|
72
Modules/StinkyCache.lua
Normal file
72
Modules/StinkyCache.lua
Normal file
@@ -0,0 +1,72 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "StinkyCache"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.StinkyCache = {}
|
||||
function shared.StinkyCache.Init()
|
||||
shared.stinkyCache = {
|
||||
stinkies = {},
|
||||
}
|
||||
|
||||
---@param name string
|
||||
local function AskCommander(name)
|
||||
if Heimdall_Data.config.stinkyCache.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Asking commander %s about %s",
|
||||
ModuleName,
|
||||
Heimdall_Data.config.stinkyCache.commander,
|
||||
name
|
||||
)
|
||||
)
|
||||
end
|
||||
local messageParts = { "isstinky", name }
|
||||
local message = table.concat(messageParts, "|")
|
||||
SendAddonMessage(
|
||||
Heimdall_Data.config.addonPrefix,
|
||||
message,
|
||||
"WHISPER",
|
||||
Heimdall_Data.config.stinkyCache.commander
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
local addonMessageFrame = CreateFrame("Frame")
|
||||
addonMessageFrame:RegisterEvent("CHAT_MSG_ADDON")
|
||||
addonMessageFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
|
||||
if sender == Heimdall_Data.config.stinkyCache.commander then
|
||||
if Heimdall_Data.config.stinkyCache.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Received stinky from commander %s: %s",
|
||||
ModuleName,
|
||||
Heimdall_Data.config.stinkyCache.commander,
|
||||
msg
|
||||
)
|
||||
)
|
||||
end
|
||||
local parts = { strsplit("|", msg) }
|
||||
local name, value = parts[1], parts[2]
|
||||
shared.stinkyCache.stinkies[name] = { value = value, timestamp = time() }
|
||||
else
|
||||
if Heimdall_Data.config.stinkyCache.debug then
|
||||
print(string.format("[%s] Received stinky from non-commander %s: %s", ModuleName, sender, msg))
|
||||
end
|
||||
local parts = { strsplit("|", msg) }
|
||||
local command, name = parts[1], parts[2]
|
||||
if parts[1] == "isstinky" then local res = Heimdall_Data.config.stinkies[parts[2]] end
|
||||
end
|
||||
end)
|
||||
|
||||
setmetatable(shared.stinkyCache.stinkies, {
|
||||
__index = function(self, key)
|
||||
local value = rawget(self, key)
|
||||
local now = GetTime()
|
||||
if value == nil or now - value.timestamp > Heimdall_Data.config.stinkyCache.ttl then AskCommander(key) end
|
||||
return rawget(self, key)
|
||||
end,
|
||||
})
|
||||
print("[Heimdall] StinkyCache module loaded")
|
||||
end
|
@@ -1,109 +1,277 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "StinkyTracker"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.StinkyTracker = {}
|
||||
function shared.StinkyTracker.Init()
|
||||
shared.stinkyTracker = {
|
||||
stinkies = ReactiveValue.new({})
|
||||
stinkies = ReactiveValue.new({}),
|
||||
}
|
||||
|
||||
local whoRegex = "([^ -/]+)-?%w*/(%w+)"
|
||||
---@param msg string
|
||||
---@return table<string, stinky>
|
||||
local function ParseWho(msg)
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Parsing WHO message: '%s'", ModuleName, msg))
|
||||
end
|
||||
local stinkies = {}
|
||||
for name, class in string.gmatch(msg, whoRegex) do
|
||||
stinkies[name] = {
|
||||
name = name,
|
||||
class = class,
|
||||
seenAt = GetTime(),
|
||||
hostile = true
|
||||
hostile = true,
|
||||
}
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Found hostile player: %s (%s) at %s",
|
||||
ModuleName,
|
||||
name,
|
||||
class,
|
||||
date("%H:%M:%S", time())
|
||||
)
|
||||
)
|
||||
shared.dumpTable(stinkies)
|
||||
end
|
||||
end
|
||||
return stinkies
|
||||
end
|
||||
|
||||
local seeRegex = "I see %((%w+)%) ([^ -/]+)-?%w*/(%w+)"
|
||||
---@param msg string
|
||||
---@return table<string, stinky>
|
||||
local function ParseSee(msg)
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Parsing SEE message: '%s'", ModuleName, msg))
|
||||
end
|
||||
local stinkies = {}
|
||||
local aggression, name, class = string.match(msg, seeRegex)
|
||||
if not name or not class then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Error: Invalid SEE message format", ModuleName))
|
||||
end
|
||||
return stinkies
|
||||
end
|
||||
local stinky = {
|
||||
name = name,
|
||||
class = class,
|
||||
seenAt = GetTime(),
|
||||
hostile = aggression == "Hostile"
|
||||
hostile = aggression == "hostile",
|
||||
}
|
||||
stinkies[name] = stinky
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Found stinky in SEE: %s (%s) - %s at %s",
|
||||
ModuleName,
|
||||
name,
|
||||
class,
|
||||
aggression,
|
||||
date("%H:%M:%S", time())
|
||||
)
|
||||
)
|
||||
shared.dumpTable(stinkies)
|
||||
end
|
||||
return stinkies
|
||||
end
|
||||
local arrivedRegex = "([^ -/]+)-?%w* of class (%w+)"
|
||||
local arrivedRegexAlt = "([^ -/]+)-?%w* %(!!!!%) of class (%w+)"
|
||||
|
||||
local arrivedRegex = "([^ -/]+)-?%w*; c:([^;]+)"
|
||||
local arrivedRegexAlt = "([^ -/]+)-?%w*%(!!!!%); c:([^;]+)"
|
||||
---@param msg string
|
||||
---@return table<string, stinky>
|
||||
local function ParseArrived(msg)
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("%s: Parsing arrived message: %s", ModuleName, msg))
|
||||
end
|
||||
local stinkies = {}
|
||||
local name, class = string.match(msg, arrivedRegex)
|
||||
if not name or not class then
|
||||
name, class = string.match(msg, arrivedRegexAlt)
|
||||
end
|
||||
if not name or not class then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("%s: No valid stinky found in arrived message", ModuleName))
|
||||
end
|
||||
return stinkies
|
||||
end
|
||||
local stinky = {
|
||||
name = name,
|
||||
class = class,
|
||||
seenAt = GetTime(),
|
||||
hostile = true
|
||||
hostile = true,
|
||||
}
|
||||
stinkies[name] = stinky
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("%s: Found stinky in arrived: %s/%s", ModuleName, name, class))
|
||||
shared.dumpTable(stinkies)
|
||||
end
|
||||
return stinkies
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("CHAT_MSG_CHANNEL")
|
||||
frame:SetScript("OnEvent", function(self, event, msg, sender, ...)
|
||||
if not Heimdall_Data.config.stinkyTracker.enabled then return end
|
||||
--if Heimdall_Data.config.stinkyTracker.debug then
|
||||
-- print(string.format("[%s] Event received: %s from %s", ModuleName, event, sender))
|
||||
--end
|
||||
if not Heimdall_Data.config.stinkyTracker.enabled then
|
||||
--if Heimdall_Data.config.stinkyTracker.debug then
|
||||
-- print(string.format("[%s] Module disabled, ignoring event", ModuleName))
|
||||
--end
|
||||
return
|
||||
end
|
||||
local channelId = select(6, ...)
|
||||
local _, channelname = GetChannelName(channelId)
|
||||
if channelname ~= Heimdall_Data.config.stinkyTracker.masterChannel then return end
|
||||
local ok = false
|
||||
for _, channel in pairs(Heimdall_Data.config.stinkyTracker.channels) do
|
||||
if channel == channelname then
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not ok then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Ignoring message from non-master channel: %s", ModuleName, channelname))
|
||||
end
|
||||
return
|
||||
end
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
|
||||
shared.dumpTable(Heimdall_Data.config.stinkyTracker)
|
||||
end
|
||||
|
||||
if string.find(msg, "^who:") then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Processing WHO message from %s", ModuleName, sender))
|
||||
end
|
||||
local whoStinkies = ParseWho(msg)
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Found stinkies in WHO message", ModuleName))
|
||||
end
|
||||
for name, stinky in pairs(whoStinkies) do
|
||||
if stinky.hostile then
|
||||
shared.stinkyTracker.stinkies[name] = stinky
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(
|
||||
string.format("[%s] Added hostile stinky from WHO: %s (%s)", ModuleName, name, stinky.class)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if string.find(msg, "^I see") then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Processing SEE message from %s", ModuleName, sender))
|
||||
end
|
||||
local seeStinkies = ParseSee(msg)
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Found stinkies in SEE message", ModuleName))
|
||||
end
|
||||
for name, stinky in pairs(seeStinkies) do
|
||||
if stinky.hostile then
|
||||
shared.stinkyTracker.stinkies[name] = stinky
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(
|
||||
string.format("[%s] Added hostile stinky from SEE: %s (%s)", ModuleName, name, stinky.class)
|
||||
)
|
||||
end
|
||||
end
|
||||
if not stinky.hostile then
|
||||
shared.stinkyTracker.stinkies[name] = nil
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Removed non-hostile stinky from SEE: %s", ModuleName, name))
|
||||
end
|
||||
end
|
||||
end
|
||||
if string.find(msg, " and guild ") then
|
||||
end
|
||||
if string.find(msg, "arrived to") or string.find(msg, "moved to") then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Processing ARRIVED message from %s", ModuleName, sender))
|
||||
end
|
||||
local arrivedStinkies = ParseArrived(msg)
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Found stinkies in ARRIVED message", ModuleName))
|
||||
end
|
||||
for name, stinky in pairs(arrivedStinkies) do
|
||||
shared.stinkyTracker.stinkies[name] = stinky
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Added stinky from ARRIVED: %s (%s)", ModuleName, name, stinky.class))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Log total stinky count after processing
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
local count = 0
|
||||
for _ in pairs(shared.stinkyTracker.stinkies:get()) do
|
||||
count = count + 1
|
||||
end
|
||||
print(string.format("[%s] Current total stinkies tracked: %d", ModuleName, count))
|
||||
end
|
||||
|
||||
for name, stinky in pairs(shared.stinkyTracker.stinkies) do
|
||||
if Heimdall_Data.config.agents[name] then
|
||||
shared.stinkyTracker.stinkies[name] = nil
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Removed agent from stinkies: %s", ModuleName, name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - StinkyTracker loaded")
|
||||
local targetFrame = CreateFrame("Frame")
|
||||
targetFrame:RegisterEvent("UNIT_TARGET")
|
||||
targetFrame:SetScript("OnEvent", function(self, event, unit)
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Event received: %s for unit: %s", ModuleName, event, unit or "target"))
|
||||
end
|
||||
unit = "target"
|
||||
|
||||
if not Heimdall_Data.config.stinkyTracker.enabled then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring event", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local name = UnitName(unit)
|
||||
if not UnitIsPlayer(unit) then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Target %s is not a player, nothing to do", ModuleName, name))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local enemy = UnitCanAttack("player", unit)
|
||||
if enemy then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Target %s is enemy - tracking as stinky", ModuleName, name))
|
||||
end
|
||||
shared.stinkyTracker.stinkies[name] = {
|
||||
name = name,
|
||||
class = UnitClass(unit),
|
||||
seenAt = GetTime(),
|
||||
hostile = true,
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
if not shared.stinkyTracker.stinkies[name] then
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Target %s is friendly and not stinky, nothing to do", ModuleName, name))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.stinkyTracker.debug then
|
||||
print(string.format("[%s] Target %s is friendly and stinky - removing from stinkies", ModuleName, name))
|
||||
end
|
||||
shared.stinkyTracker.stinkies[name] = nil
|
||||
end)
|
||||
|
||||
if Heimdall_Data.config.stinkyTracker.debug then print(string.format("[%s] Module initialized", ModuleName)) end
|
||||
print("[Heimdall] StinkyTracker loaded")
|
||||
end
|
||||
|
@@ -1,6 +1,6 @@
|
||||
local addonname, shared = ...
|
||||
local _, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Whoer"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Whoer = {}
|
||||
@@ -31,7 +31,7 @@ function shared.Whoer.Init()
|
||||
---@return Player
|
||||
new = function(name, guild, race, class, zone)
|
||||
local self = setmetatable({}, {
|
||||
__index = Player
|
||||
__index = Player,
|
||||
})
|
||||
self.name = name
|
||||
self.guild = guild
|
||||
@@ -46,31 +46,17 @@ function shared.Whoer.Init()
|
||||
end,
|
||||
---@return string
|
||||
ToString = function(self)
|
||||
local out = string.format("%s %s %s\nFirst: %s Last: %s Seen: %3d",
|
||||
local out = string.format(
|
||||
"%s %s %s\nFirst: %s Last: %s Seen: %3d",
|
||||
shared.padString(self.name, 16, true),
|
||||
shared.padString(self.guild, 26, false),
|
||||
shared.padString(self.zone, 26, false),
|
||||
shared.padString(self.firstSeen, 10, true),
|
||||
shared.padString(self.lastSeen, 10, true),
|
||||
self.seenCount)
|
||||
self.seenCount
|
||||
)
|
||||
return string.format("|cFF%s%s|r", shared.classColors[self.class], out)
|
||||
end,
|
||||
---@return string
|
||||
NotifyMessage = function(self)
|
||||
local text = string.format(
|
||||
"%s %s of class %s, race %s (%s) and guild %s in %s, first seen: %s, last seen: %s, times seen: %d",
|
||||
self.name,
|
||||
self.stinky and "(!!!!)" or "",
|
||||
self.class,
|
||||
self.race,
|
||||
tostring(shared.raceMap[self.race]),
|
||||
self.guild,
|
||||
self.zone,
|
||||
self.firstSeen,
|
||||
self.lastSeen,
|
||||
self.seenCount)
|
||||
return text
|
||||
end
|
||||
}
|
||||
|
||||
---@class WHOQuery
|
||||
@@ -82,83 +68,258 @@ function shared.Whoer.Init()
|
||||
---@return WHOQuery
|
||||
new = function(query, filters)
|
||||
local self = setmetatable({}, {
|
||||
__index = WHOQuery
|
||||
__index = WHOQuery,
|
||||
})
|
||||
self.query = query
|
||||
self.filters = filters
|
||||
return self
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---@alias WHOFilter fun(name: string, guild: string, level: number, race: string, class: string, zone: string): boolean
|
||||
---@class WHOFilter
|
||||
---@field Run fun(name: string, guild: string, level: number, race: string, class: string, zone: string): boolean
|
||||
---@field key string
|
||||
---@type WHOFilter
|
||||
local NotSiegeOfOrgrimmarFilter = function(name, guild, level, race, class, zone)
|
||||
if not zone then
|
||||
return false
|
||||
end
|
||||
local NotSiegeOfOrgrimmarFilter = {
|
||||
Run = function(name, guild, level, race, class, zone)
|
||||
if not zone then return false end
|
||||
return zone ~= "Siege of Orgrimmar"
|
||||
end
|
||||
end,
|
||||
key = "notsoo",
|
||||
}
|
||||
---@type WHOFilter
|
||||
local AllianceFilter = function(name, guild, level, race, class, zone)
|
||||
local AllianceFilter = {
|
||||
Run = function(name, guild, level, race, class, zone)
|
||||
if not race then return false end
|
||||
if not shared.raceMap[race] then return false end
|
||||
return shared.raceMap[race] == "Alliance"
|
||||
end,
|
||||
key = "ally",
|
||||
}
|
||||
|
||||
---@class WhoQueryService
|
||||
---@field queries WHOQuery[]
|
||||
---@field filters WHOFilter[]
|
||||
---@field getFilter fun(key: string): WHOFilter?
|
||||
---@field WhoQueryToString fun(query: WHOQuery): string
|
||||
---@field WhoQueryFromString fun(query: string): WHOQuery
|
||||
---@field WhoQueriesToString fun(queries: WHOQuery[]): string
|
||||
---@field WhoQueriesFromString fun(queries: string): WHOQuery[]
|
||||
shared.WhoQueryService = {
|
||||
queries = {},
|
||||
filters = {
|
||||
NotSiegeOfOrgrimmarFilter,
|
||||
AllianceFilter,
|
||||
},
|
||||
---@param key string
|
||||
---@return WHOFilter?
|
||||
getFilter = function(key)
|
||||
for _, filter in pairs(shared.WhoQueryService.filters) do
|
||||
if filter.key == key then return filter end
|
||||
end
|
||||
return nil
|
||||
end,
|
||||
---@param query WHOQuery
|
||||
---@return string
|
||||
WhoQueryToString = function(query)
|
||||
local ret = ""
|
||||
ret = ret .. query.query
|
||||
ret = ret .. ";"
|
||||
for _, filter in pairs(query.filters) do
|
||||
ret = ret .. filter.key .. ";"
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
---@param queries WHOQuery[]
|
||||
---@return string
|
||||
WhoQueriesToString = function(queries)
|
||||
local ret = ""
|
||||
for _, query in pairs(queries) do
|
||||
ret = ret .. shared.WhoQueryService.WhoQueryToString(query) .. "\n"
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
---@param query string
|
||||
---@return WHOQuery
|
||||
WhoQueryFromString = function(query)
|
||||
local queryParts = shared.Split(query, ";")
|
||||
local filters = {}
|
||||
for _, filterKey in pairs(queryParts) do
|
||||
local filter = shared.WhoQueryService.getFilter(filterKey)
|
||||
if not filter then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Filter %s not found", ModuleName, filterKey))
|
||||
end
|
||||
else
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Filter %s found", ModuleName, filterKey))
|
||||
end
|
||||
|
||||
local whoQueryIdx = 1
|
||||
---@type WHOQuery[]
|
||||
local whoQueries = {
|
||||
WHOQuery.new("g-\"БеспредеЛ\"", {}),
|
||||
--WHOQuery.new("g-\"Dovahkin\"", {}),
|
||||
WHOQuery.new(
|
||||
"z-\"Orgrimmar\" z-\"Durotar\" z-\"Valley of Trials\" r-\"Human\" r-\"Dwarf\" r-\"Night Elf\"",
|
||||
{ NotSiegeOfOrgrimmarFilter, AllianceFilter }),
|
||||
WHOQuery.new(
|
||||
"z-\"Orgrimmar\" z-\"Durotar\" z-\"Valley of Trials\" r-\"Gnome\" r-\"Draenei\" r-\"Worgen\"",
|
||||
{ NotSiegeOfOrgrimmarFilter, AllianceFilter }),
|
||||
WHOQuery.new(
|
||||
"z-\"Orgrimmar\" z-\"Durotar\" z-\"Valley of Trials\" r-\"Kul Tiran\" r-\"Dark Iron Dwarf\" r-\"Void Elf\"",
|
||||
{ NotSiegeOfOrgrimmarFilter, AllianceFilter }),
|
||||
WHOQuery.new(
|
||||
"z-\"Orgrimmar\" z-\"Durotar\" z-\"Valley of Trials\" r-\"Lightforged Draenei\" r-\"Mechagnome\"",
|
||||
{ NotSiegeOfOrgrimmarFilter, AllianceFilter }),
|
||||
WHOQuery.new("Kekv Firobot Tomoki", {})
|
||||
table.insert(filters, filter)
|
||||
end
|
||||
end
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] WHO query: %s with %d filters", ModuleName, queryParts[1], #filters))
|
||||
end
|
||||
shared.dumpTable(filters)
|
||||
return WHOQuery.new(queryParts[1], filters)
|
||||
end,
|
||||
---@param queryStr string
|
||||
---@return WHOQuery[]
|
||||
WhoQueriesFromString = function(queryStr)
|
||||
local queries = shared.Split(queryStr, "\n")
|
||||
local ret = {}
|
||||
for _, query in pairs(queries) do
|
||||
table.insert(ret, shared.WhoQueryService.WhoQueryFromString(query))
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
}
|
||||
local ttl = #whoQueries * 2
|
||||
shared.WhoQueryService.queries = shared.WhoQueryService.WhoQueriesFromString(Heimdall_Data.config.who.queries)
|
||||
|
||||
---@param inputZone string
|
||||
---@return boolean
|
||||
shared.Whoer.ShouldNotifyForZone = shared.Memoize(function(inputZone)
|
||||
if not Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] ShouldNotifyForZone %s", ModuleName, inputZone))
|
||||
end
|
||||
for zone, _ in pairs(Heimdall_Data.config.who.zoneNotifyFor) do
|
||||
if Heimdall_Data.config.who.debug then print(string.format("[%s] Checking zone %s", ModuleName, zone)) end
|
||||
if zone == "*" then return true end
|
||||
if string.find(inputZone, zone) then
|
||||
if not Heimdall_Data.config.who.debug then
|
||||
print(
|
||||
string.format("[%s] ShouldNotifyForZone %s is true thanks to %s", ModuleName, inputZone, zone)
|
||||
)
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
if not Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] ShouldNotifyForZone %s is false", ModuleName, inputZone))
|
||||
end
|
||||
return false
|
||||
end)
|
||||
|
||||
-----@type WHOQuery[]
|
||||
--local whoQueries = {
|
||||
-- WHOQuery.new("g-\"БеспредеЛ\"", {}),
|
||||
-- WHOQuery.new("g-\"ЗАО бещёки\"", {}),
|
||||
-- WHOQuery.new("g-\"КОНИЛИНГУСЫ\"", {}),
|
||||
-- --WHOQuery.new("g-\"Dovahkin\"", {}),
|
||||
-- WHOQuery.new(
|
||||
-- "z-\"Orgrimmar\" z-\"Durotar\" z-\"Valley of Trials\" r-\"Human\" r-\"Dwarf\" r-\"Night Elf\"",
|
||||
-- { NotSiegeOfOrgrimmarFilter, AllianceFilter }),
|
||||
-- WHOQuery.new(
|
||||
-- "z-\"Orgrimmar\" z-\"Durotar\" z-\"Valley of Trials\" r-\"Gnome\" r-\"Draenei\" r-\"Worgen\"",
|
||||
-- { NotSiegeOfOrgrimmarFilter, AllianceFilter }),
|
||||
-- WHOQuery.new(
|
||||
-- "z-\"Orgrimmar\" z-\"Durotar\" z-\"Valley of Trials\" r-\"Kul Tiran\" r-\"Dark Iron Dwarf\" r-\"Void Elf\"",
|
||||
-- { NotSiegeOfOrgrimmarFilter, AllianceFilter }),
|
||||
-- WHOQuery.new(
|
||||
-- "z-\"Orgrimmar\" z-\"Durotar\" z-\"Valley of Trials\" r-\"Lightforged Draenei\" r-\"Mechagnome\"",
|
||||
-- { NotSiegeOfOrgrimmarFilter, AllianceFilter }),
|
||||
-- WHOQuery.new("Kekv Firobot Tomoki Mld Alltros", {})
|
||||
--}
|
||||
local whoQueryIdx = 1
|
||||
---@type WHOQuery?
|
||||
local lastQuery = nil
|
||||
|
||||
---@param player Player
|
||||
---@return string?
|
||||
local function Notify(player)
|
||||
if not Heimdall_Data.config.who.enabled then return end
|
||||
if not player then return string.format("Cannot notify for nil player %s", tostring(player)) end
|
||||
if not Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
return string.format("Not notifying for zone %s",
|
||||
tostring(player.zone))
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Processing notification for player: %s", ModuleName, player.name))
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Player details - Guild: %s, Race: %s, Class: %s, Zone: %s",
|
||||
ModuleName,
|
||||
player.guild,
|
||||
player.race,
|
||||
player.class,
|
||||
player.zone
|
||||
)
|
||||
)
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Player history - First seen: %s, Last seen: %s, Seen count: %d",
|
||||
ModuleName,
|
||||
player.firstSeen,
|
||||
player.lastSeen,
|
||||
player.seenCount
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
local text = player:NotifyMessage()
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.who.notifyChannel,
|
||||
message = text
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
if not Heimdall_Data.config.who.enabled then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Module disabled, skipping notification", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.who.doWhisper then
|
||||
for _, name in pairs(Heimdall_Data.config.whisperNotify) do
|
||||
if not player then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Error: Cannot notify for nil player", ModuleName))
|
||||
end
|
||||
return string.format("Cannot notify for nil player %s", tostring(player))
|
||||
end
|
||||
|
||||
if not shared.Whoer.ShouldNotifyForZone(player.zone) then
|
||||
--if not Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(
|
||||
string.format("[%s] Skipping notification - Zone '%s' not in notify list", ModuleName, player.zone)
|
||||
)
|
||||
end
|
||||
return string.format("Not notifying for zone %s", tostring(player.zone))
|
||||
end
|
||||
|
||||
for _, channel in pairs(Heimdall_Data.config.who.channels) do
|
||||
local locale = shared.GetLocaleForChannel(channel)
|
||||
local text = string.format(
|
||||
shared._L("whoerNew", locale),
|
||||
player.name,
|
||||
player.stinky and "(!!!!)" or "",
|
||||
shared._L(player.class, locale),
|
||||
--shared._L(player.race, locale),
|
||||
shared._L(shared.raceMap[player.race] or "unknown", locale),
|
||||
player.guild,
|
||||
shared._L(player.zone, locale)
|
||||
)
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "WHISPER",
|
||||
data = name,
|
||||
message = text
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text,
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Queuing channel notification", ModuleName))
|
||||
shared.dumpTable(msg)
|
||||
end
|
||||
table.insert(shared.networkMessenger.queue, msg)
|
||||
end
|
||||
|
||||
--if Heimdall_Data.config.who.doWhisper then
|
||||
-- if Heimdall_Data.config.who.debug then
|
||||
-- print(string.format("[%s] Processing whisper notifications for %d recipients", ModuleName,
|
||||
-- #Heimdall_Data.config.whisperNotify))
|
||||
-- end
|
||||
-- for _, name in pairs(Heimdall_Data.config.whisperNotify) do
|
||||
-- ---@type Message
|
||||
-- local msg = {
|
||||
-- channel = "W",
|
||||
-- data = name,
|
||||
-- message = text
|
||||
-- }
|
||||
-- if Heimdall_Data.config.who.debug then
|
||||
-- print(string.format("[%s] Queuing whisper to %s", ModuleName, name))
|
||||
-- end
|
||||
-- --table.insert(shared.messenger.queue, msg)
|
||||
-- table.insert(shared.networkMessenger.queue, msg)
|
||||
-- end
|
||||
--end
|
||||
|
||||
return nil
|
||||
end
|
||||
---@param player Player
|
||||
@@ -167,37 +328,49 @@ function shared.Whoer.Init()
|
||||
local function NotifyZoneChanged(player, zone)
|
||||
if not Heimdall_Data.config.who.enabled then return end
|
||||
if not player then return string.format("Cannot notify for nil player %s", tostring(player)) end
|
||||
if not Heimdall_Data.config.who.zoneNotifyFor[zone]
|
||||
and not Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
--if not Heimdall_Data.config.who.zoneNotifyFor[zone]
|
||||
-- and not Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
if not shared.Whoer.ShouldNotifyForZone(zone) and not shared.Whoer.ShouldNotifyForZone(player.zone) then
|
||||
return string.format("Not notifying for zones %s and %s", tostring(zone), tostring(player.zone))
|
||||
end
|
||||
local text = string.format("%s of class %s (%s - %s) and guild %s moved to %s",
|
||||
for _, channel in pairs(Heimdall_Data.config.who.channels) do
|
||||
local locale = shared.GetLocaleForChannel(channel)
|
||||
local text = string.format(
|
||||
shared._L("whoerMoved", locale),
|
||||
player.name,
|
||||
player.class,
|
||||
player.race,
|
||||
shared.raceMap[player.race] or "Unknown",
|
||||
player.stinky and "(!!!!)" or "",
|
||||
shared._L(player.class, locale),
|
||||
--shared._L(player.race, locale),
|
||||
shared._L(shared.raceMap[player.race] or "unknown", locale),
|
||||
player.guild,
|
||||
zone)
|
||||
shared._L(zone, locale)
|
||||
)
|
||||
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.who.notifyChannel,
|
||||
message = text
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text,
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Queuing channel notification", ModuleName))
|
||||
shared.dumpTable(msg)
|
||||
end
|
||||
table.insert(shared.networkMessenger.queue, msg)
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.who.doWhisper then
|
||||
for _, name in pairs(Heimdall_Data.config.whisperNotify) do
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "WHISPER",
|
||||
data = name,
|
||||
message = text
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
end
|
||||
end
|
||||
--if Heimdall_Data.config.who.doWhisper then
|
||||
-- for _, name in pairs(Heimdall_Data.config.whisperNotify) do
|
||||
-- ---@type Message
|
||||
-- local msg = {
|
||||
-- channel = "W",
|
||||
-- data = name,
|
||||
-- message = text
|
||||
-- }
|
||||
-- --table.insert(shared.messenger.queue, msg)
|
||||
-- table.insert(shared.networkMessenger.queue, msg)
|
||||
-- end
|
||||
--end
|
||||
|
||||
return nil
|
||||
end
|
||||
@@ -206,36 +379,50 @@ function shared.Whoer.Init()
|
||||
local function NotifyGone(player)
|
||||
if not Heimdall_Data.config.who.enabled then return end
|
||||
if not player then return string.format("Cannot notify for nil player %s", tostring(player)) end
|
||||
if not Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
return string.format("Not notifying for zone %s",
|
||||
tostring(player.zone))
|
||||
--if not Heimdall_Data.config.who.zoneNotifyFor[player.zone] then
|
||||
if not shared.Whoer.ShouldNotifyForZone(player.zone) then
|
||||
return string.format("Not notifying for zone %s", tostring(player.zone))
|
||||
end
|
||||
|
||||
local text = string.format("%s of class %s and guild %s left %s",
|
||||
for _, channel in pairs(Heimdall_Data.config.who.channels) do
|
||||
local locale = shared.GetLocaleForChannel(channel)
|
||||
local text = string.format(
|
||||
shared._L("whoerGone", locale),
|
||||
player.name,
|
||||
player.class,
|
||||
player.stinky and "(!!!!)" or "",
|
||||
shared._L(player.class, locale),
|
||||
--shared._L(player.race, locale),
|
||||
shared._L(shared.raceMap[player.race] or "unknown", locale),
|
||||
player.guild,
|
||||
player.zone)
|
||||
shared._L(player.zone, locale)
|
||||
)
|
||||
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.who.notifyChannel,
|
||||
message = text
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text,
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Queuing channel notification", ModuleName))
|
||||
shared.dumpTable(msg)
|
||||
end
|
||||
--table.insert(shared.messenger.queue, msg)
|
||||
table.insert(shared.networkMessenger.queue, msg)
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.who.doWhisper then
|
||||
for _, name in pairs(Heimdall_Data.config.whisperNotify) do
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "WHISPER",
|
||||
data = name,
|
||||
message = text
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
end
|
||||
end
|
||||
--if Heimdall_Data.config.who.doWhisper then
|
||||
-- for _, name in pairs(Heimdall_Data.config.whisperNotify) do
|
||||
-- ---@type Message
|
||||
-- local msg = {
|
||||
-- channel = "W",
|
||||
-- data = name,
|
||||
-- message = text
|
||||
-- }
|
||||
-- --table.insert(shared.messenger.queue, msg)
|
||||
-- table.insert(shared.networkMessenger.queue, msg)
|
||||
-- end
|
||||
--end
|
||||
|
||||
return nil
|
||||
end
|
||||
@@ -243,60 +430,126 @@ function shared.Whoer.Init()
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("WHO_LIST_UPDATE")
|
||||
frame:SetScript("OnEvent", function(self, event, ...)
|
||||
if not Heimdall_Data.config.who.enabled then return end
|
||||
---@type WHOQuery?
|
||||
local query = lastQuery
|
||||
if not query then
|
||||
print("No query wtf?")
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] WHO list update received", ModuleName))
|
||||
print(string.format("[%s] Query index: %d/%d", ModuleName, whoQueryIdx, #shared.WhoQueryService.queries))
|
||||
end
|
||||
|
||||
if not Heimdall_Data.config.who.enabled then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Module disabled, ignoring WHO update", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, GetNumWhoResults() do
|
||||
local name, guild, level, race, class, zone = GetWhoInfo(i)
|
||||
local continue = false
|
||||
--print(name, guild, level, race, class, zone)
|
||||
---@type WHOQuery?
|
||||
local query = lastQuery
|
||||
if not query then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Error: No active WHO query found", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local results = GetNumWhoResults()
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Processing %d WHO results for query: %s", ModuleName, results, query.query))
|
||||
end
|
||||
|
||||
for i = 1, results do
|
||||
local name, guild, level, race, class, zone = GetWhoInfo(i)
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(
|
||||
string.format("[%s] Processing result %d/%d: %s/%s/%s", ModuleName, i, results, name, class, zone)
|
||||
)
|
||||
end
|
||||
|
||||
local continue = false
|
||||
---@type WHOFilter[]
|
||||
local filters = query.filters
|
||||
for _, filter in pairs(filters) do
|
||||
if not filter(name, guild, level, race, class, zone) then
|
||||
-- Mega scuffed, yes...
|
||||
-- But wow does not have gotos
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(
|
||||
string.format("[%s] Running filter %s on %s/%s/%s", ModuleName, filter.key, name, class, zone)
|
||||
)
|
||||
end
|
||||
if not filter.Run(name, guild, level, race, class, zone) then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(
|
||||
string.format("[%s] Player %s filtered out by WHO filter %s", ModuleName, name, filter.key)
|
||||
)
|
||||
end
|
||||
continue = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.who.ignored[name] then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Ignoring blacklisted player: %s", ModuleName, name))
|
||||
end
|
||||
continue = true
|
||||
end
|
||||
end
|
||||
if Heimdall_Data.config.who.ignored[name] then continue = true end
|
||||
--print(continue)
|
||||
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Player %s is not blacklisted", ModuleName, name))
|
||||
end
|
||||
if not continue then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Player %s is not filtered out", ModuleName, name))
|
||||
end
|
||||
local timestamp = date("%Y-%m-%dT%H:%M:%S")
|
||||
local player = HeimdallStinkies[name]
|
||||
if not player then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] New player detected: %s (%s) in %s", ModuleName, name, class, zone))
|
||||
end
|
||||
|
||||
player = Player.new(name, guild, race, class, zone)
|
||||
if not Heimdall_Data.who then Heimdall_Data.who = {} end
|
||||
if not Heimdall_Data.who.data then Heimdall_Data.who.data = {} end
|
||||
local existing = Heimdall_Data.who.data[name]
|
||||
|
||||
if existing then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Found existing data for %s - Last seen: %s, Count: %d",
|
||||
ModuleName,
|
||||
name,
|
||||
existing.lastSeen or "never",
|
||||
existing.seenCount or 0
|
||||
)
|
||||
)
|
||||
end
|
||||
player.lastSeen = existing.lastSeen or "never"
|
||||
player.firstSeen = existing.firstSeen or "never"
|
||||
player.seenCount = existing.seenCount or 0
|
||||
end
|
||||
|
||||
if player.firstSeen == "never" then
|
||||
player.firstSeen = timestamp
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] First time seeing player: %s at %s", ModuleName, name, timestamp))
|
||||
end
|
||||
end
|
||||
|
||||
local stinky = Heimdall_Data.config.stinkies[name]
|
||||
local stinky = shared.IsStinky(name)
|
||||
if stinky then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Player %s marked as stinky!", ModuleName, name))
|
||||
end
|
||||
player.stinky = true
|
||||
--PlaySoundFile("Interface\\Sounds\\Domination.ogg", "Master")
|
||||
else
|
||||
--PlaySoundFile("Interface\\Sounds\\Cloak.ogg", "Master")
|
||||
-- else
|
||||
-- PlaySoundFile("Interface\\Sounds\\Cloak.ogg", "Master")
|
||||
end
|
||||
|
||||
local err = Notify(player)
|
||||
if err then
|
||||
print(string.format("Error notifying for %s: %s", tostring(name), tostring(err)))
|
||||
print(
|
||||
string.format("[%s] Error notifying for %s: %s", ModuleName, tostring(name), tostring(err))
|
||||
)
|
||||
end
|
||||
|
||||
player.lastSeen = timestamp
|
||||
@@ -306,10 +559,19 @@ function shared.Whoer.Init()
|
||||
|
||||
player.lastSeenInternal = GetTime()
|
||||
if player.zone ~= zone then
|
||||
local err = NotifyZoneChanged(player, zone)
|
||||
if err then
|
||||
print(string.format("Error notifying for %s: %s", tostring(name), tostring(err)))
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Player %s zone changed from %s to %s",
|
||||
ModuleName,
|
||||
name,
|
||||
player.zone,
|
||||
zone
|
||||
)
|
||||
)
|
||||
end
|
||||
local err = NotifyZoneChanged(player, zone)
|
||||
if err then print(string.format("Error notifying for %s: %s", tostring(name), tostring(err))) end
|
||||
end
|
||||
player.zone = zone
|
||||
player.lastSeen = timestamp
|
||||
@@ -345,13 +607,32 @@ function shared.Whoer.Init()
|
||||
local function DoQuery()
|
||||
if not Heimdall_Data.config.who.enabled then return end
|
||||
|
||||
local query = whoQueries[whoQueryIdx]
|
||||
whoQueryIdx = whoQueryIdx + 1
|
||||
if whoQueryIdx > #whoQueries then
|
||||
whoQueryIdx = 1
|
||||
local query = shared.WhoQueryService.queries[whoQueryIdx]
|
||||
if not query then
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Error: No WHO query found to run at index %d", ModuleName, whoQueryIdx))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(
|
||||
string.format(
|
||||
"[%s] Running WHO query %d/%d: %s",
|
||||
ModuleName,
|
||||
whoQueryIdx,
|
||||
#shared.WhoQueryService.queries,
|
||||
query.query
|
||||
)
|
||||
)
|
||||
print(string.format("[%s] Query has %d filters", ModuleName, #query.filters))
|
||||
for i, filter in ipairs(query.filters) do
|
||||
print(string.format("[%s] Filter %d: %s", ModuleName, i, filter.key))
|
||||
end
|
||||
end
|
||||
whoQueryIdx = whoQueryIdx + 1
|
||||
if whoQueryIdx > #shared.WhoQueryService.queries then whoQueryIdx = 1 end
|
||||
lastQuery = query
|
||||
--print(string.format("Running who query: %s", tostring(query.query)))
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
SetWhoToUI(1)
|
||||
SendWho(query.query)
|
||||
@@ -363,5 +644,5 @@ function shared.Whoer.Init()
|
||||
Tick()
|
||||
end
|
||||
|
||||
print("Heimdall - Whoer loaded")
|
||||
print("[Heimdall] Whoer loaded")
|
||||
end
|
||||
|
BIN
Sounds/MGSSpot.ogg
(Stored with Git LFS)
Normal file
BIN
Sounds/MGSSpot.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Sounds/MedicGangsterParadise.ogg
(Stored with Git LFS)
Normal file
BIN
Sounds/MedicGangsterParadise.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Sounds/OOF.ogg
(Stored with Git LFS)
Normal file
BIN
Sounds/OOF.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Sounds/StarScream.ogg
(Stored with Git LFS)
Normal file
BIN
Sounds/StarScream.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura1.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura1.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura10.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura10.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura100.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura100.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura101.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura101.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura102.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura102.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura103.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura103.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura104.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura104.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura105.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura105.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura106.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura106.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura107.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura107.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura108.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura108.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura109.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura109.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura11.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura11.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura110.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura110.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura111.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura111.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura112.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura112.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura113.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura113.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura114.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura114.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura115.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura115.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura116.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura116.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura117.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura117.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura118.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura118.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura119.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura119.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura12.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura12.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura120.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura120.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura121.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura121.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura122.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura122.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura123.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura123.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura124.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura124.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura125.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura125.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura126.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura126.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura127.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura127.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura128.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura128.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura129.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura129.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura13.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura13.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura130.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura130.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura131.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura131.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura132.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura132.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura133.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura133.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura134.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura134.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura135.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura135.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura136.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura136.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura137.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura137.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura138.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura138.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura139.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura139.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura14.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura14.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura140.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura140.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura141.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura141.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura142.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura142.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura143.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura143.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura144.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura144.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura145.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura145.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura15.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura15.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura16.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura16.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura17.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura17.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura18.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura18.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura19.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura19.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura2.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura2.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura20.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura20.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user