Compare commits
238 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c64a6f119c | ||
70126a8bef | |||
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
|
||||
|
88
.github/workflows/release.yml
vendored
Normal file
88
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
name: Release Workflow
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install zip
|
||||
run: sudo apt-get install zip
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.name "Git Admin"
|
||||
git config --global user.email "gitadmin@quack-lab.dev"
|
||||
|
||||
- name: Run deploy script
|
||||
run: bash deploy.sh
|
||||
|
||||
- name: Check for Existing Release Commit
|
||||
id: check_release_commit
|
||||
run: |
|
||||
# Check if the latest commit is a release commit
|
||||
if git log -1 --pretty=%B | grep -q "Release"; then
|
||||
echo "Release commit found. Skipping version bump."
|
||||
echo "::set-output name=release_commit::true"
|
||||
else
|
||||
echo "No release commit found. Proceeding with version bump."
|
||||
echo "::set-output name=release_commit::false"
|
||||
fi
|
||||
|
||||
- name: Run Release Script
|
||||
if: steps.check_release_commit.outputs.release_commit == 'false'
|
||||
run: bash release.sh
|
||||
|
||||
- name: Push Changes
|
||||
if: steps.check_release_commit.outputs.release_commit == 'false'
|
||||
run: |
|
||||
git push origin HEAD:refs/heads/master --tags
|
||||
|
||||
- name: Determine Tag
|
||||
id: determine_tag
|
||||
run: |
|
||||
# Check if the last commit has a tag
|
||||
TAG=$(git describe --tags --exact-match 2>/dev/null || echo "")
|
||||
if [ -z "$TAG" ]; then
|
||||
# Get the latest tag
|
||||
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
|
||||
# Increment the minor version
|
||||
IFS='.' read -r -a VERSION_PARTS <<< "$LATEST_TAG"
|
||||
VERSION_PARTS[2]=$((VERSION_PARTS[2]+1))
|
||||
TAG="${VERSION_PARTS[0]}.${VERSION_PARTS[1]}.${VERSION_PARTS[2]}"
|
||||
# Create a new tag
|
||||
git tag $TAG
|
||||
git push origin $TAG
|
||||
fi
|
||||
echo "::set-output name=tag::$TAG"
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: token ${{ secrets.JEBENI_TOKEN }}" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"tag_name": "${{ steps.determine_tag.outputs.tag }}",
|
||||
"name": "${{ steps.determine_tag.outputs.tag }}",
|
||||
"draft": false,
|
||||
"prerelease": false
|
||||
}' \
|
||||
http://srv-captain--git:3000/api/v1/repos/dave/wow-Heimdall/releases
|
||||
|
||||
- name: Upload Release Asset
|
||||
run: |
|
||||
RELEASE_ID=$(curl -s \
|
||||
-H "Authorization: token ${{ secrets.JEBENI_TOKEN }}" \
|
||||
http://srv-captain--git:3000/api/v1/repos/dave/wow-Heimdall/releases/tags/${{ steps.determine_tag.outputs.tag }} | jq -r '.id')
|
||||
curl -X POST \
|
||||
-H "Authorization: token ${{ secrets.JEBENI_TOKEN }}" \
|
||||
-H "Content-Type: application/zip" \
|
||||
-H "Content-Disposition: attachment; filename=Heimdall.zip" \
|
||||
--data-binary @Heimdall.zip \
|
||||
http://srv-captain--git:3000/api/v1/repos/dave/wow-Heimdall/releases/${RELEASE_ID}/assets
|
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
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"Lua.diagnostics.globals": [
|
||||
"UIParent"
|
||||
"UIParent",
|
||||
"BattlefieldMinimap"
|
||||
]
|
||||
}
|
1101
Heimdall.lua
1101
Heimdall.lua
File diff suppressed because it is too large
Load Diff
63
Heimdall.toc
63
Heimdall.toc
@@ -1,27 +1,36 @@
|
||||
## Interface: 70300
|
||||
## Title: Heimdall
|
||||
## Version: 3.0.0
|
||||
## Notes: Watches over areas and alerts when hostiles spotted
|
||||
## Author: Cyka
|
||||
## SavedVariables: Heimdall_Data
|
||||
|
||||
#core
|
||||
Modules/CLEUParser.lua
|
||||
Modules/ReactiveValue.lua
|
||||
Modules/DumpTable.lua
|
||||
Modules/Spotter.lua
|
||||
Modules/Whoer.lua
|
||||
Modules/Messenger.lua
|
||||
Modules/DeathReporter.lua
|
||||
Modules/Inviter.lua
|
||||
Modules/Dueler.lua
|
||||
Modules/Bully.lua
|
||||
Modules/AgentTracker.lua
|
||||
Modules/Emoter.lua
|
||||
Modules/Echoer.lua
|
||||
Modules/Macroer.lua
|
||||
Modules/Commander.lua
|
||||
Modules/StinkyTracker.lua
|
||||
Modules/CombatAlerter.lua
|
||||
Modules/Config.lua
|
||||
Heimdall.lua
|
||||
## Interface: 70300
|
||||
## Title: Heimdall
|
||||
## Version: 3.10.1
|
||||
## Notes: Watches over areas and alerts when hostiles spotted
|
||||
## Author: Cyka
|
||||
## SavedVariables: Heimdall_Data, Heimdall_Achievements
|
||||
|
||||
_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
|
||||
Modules/Bully.lua
|
||||
Modules/AgentTracker.lua
|
||||
Modules/Emoter.lua
|
||||
Modules/Echoer.lua
|
||||
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 c0337ef97f
297
Modules/AchievementSniffer.lua
Normal file
297
Modules/AchievementSniffer.lua
Normal file
@@ -0,0 +1,297 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
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,109 @@
|
||||
local addonname, 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)
|
||||
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
|
||||
end
|
||||
--shared.dumpTable(Heimdall_Data.config.agents)
|
||||
|
||||
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
|
||||
|
107
Modules/BonkDetector.lua
Normal file
107
Modules/BonkDetector.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
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
|
||||
|
||||
local 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
|
||||
local sourceGUID = CLEUParser.GetSourceGUID(...)
|
||||
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
|
||||
|
||||
local 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
|
||||
local destinationGUID = CLEUParser.GetDestGUID(...)
|
||||
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,13 @@
|
||||
local addonname, 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
|
||||
|
@@ -1289,4 +1289,4 @@ frame:RegisterEvent("GUILD_ROSTER_UPDATE")
|
||||
frame:SetScript("OnEvent", function(self, event, ...)
|
||||
Init()
|
||||
end)
|
||||
Init()
|
||||
Init()
|
||||
|
@@ -1,6 +1,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "CombatAlerter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.CombatAlerter = {}
|
||||
@@ -9,41 +10,109 @@ 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
|
||||
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
|
||||
|
||||
local destination, err = CLEUParser.GetDestName(...)
|
||||
if err then return end
|
||||
if destination ~= UnitName("player") then return end
|
||||
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
|
||||
|
||||
local source, err = CLEUParser.GetSourceName(...)
|
||||
if err then source = "unknown" end
|
||||
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")
|
||||
---@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 ",
|
||||
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,
|
||||
GetZoneText(), GetSubZoneText(),
|
||||
shared._L("zone", locale), shared._L("subZone", locale),
|
||||
tostring(areaId),
|
||||
x * 100, y * 100
|
||||
),
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
)
|
||||
---@type Message
|
||||
local msg = {
|
||||
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,21 @@
|
||||
local addonname, 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,6 +23,12 @@ 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.",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +69,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
|
||||
if shared.Whoer.ShouldNotifyForZone(player.zone) then
|
||||
ret[player.zone] = (ret[player.zone] or 0) + 1
|
||||
end
|
||||
end
|
||||
@@ -81,11 +94,14 @@ 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
|
||||
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>
|
||||
@@ -94,7 +110,7 @@ function shared.Commander.Init()
|
||||
local who = Who(arr)
|
||||
local text = {}
|
||||
for _, line in pairs(Partition(strjoin(", ", unpack(who)), 200)) do
|
||||
text[#text + 1] = line
|
||||
text[#text + 1] = "who: " .. line
|
||||
end
|
||||
return text
|
||||
end
|
||||
@@ -103,7 +119,7 @@ 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
|
||||
if shared.Whoer.ShouldNotifyForZone(player.zone) then
|
||||
ret[player.class] = (ret[player.class] or 0) + 1
|
||||
end
|
||||
end
|
||||
@@ -111,6 +127,9 @@ function shared.Commander.Init()
|
||||
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>
|
||||
@@ -124,6 +143,10 @@ function shared.Commander.Init()
|
||||
return text
|
||||
end
|
||||
local function CountClassPartitionedStinkies()
|
||||
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" }
|
||||
@@ -131,6 +154,11 @@ function shared.Commander.Init()
|
||||
return res
|
||||
end
|
||||
local function WhoPartitionedStinkies()
|
||||
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" }
|
||||
@@ -138,23 +166,36 @@ function shared.Commander.Init()
|
||||
return res
|
||||
end
|
||||
local function CountPartitionedStinkies()
|
||||
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")
|
||||
@@ -162,62 +203,137 @@ function shared.Commander.Init()
|
||||
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
|
||||
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 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) })
|
||||
local messages = command.callback({ strsplit(",", msg) })
|
||||
if Heimdall_Data.config.commander.debug then
|
||||
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",
|
||||
channel = "C",
|
||||
data = channelname,
|
||||
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, msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
print("Heimdall - Commander loaded")
|
||||
print("[Heimdall] Commander module loaded")
|
||||
end
|
||||
|
1323
Modules/Config.lua
1323
Modules/Config.lua
File diff suppressed because it is too large
Load Diff
10
Modules/Configurator.lua
Normal file
10
Modules/Configurator.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Configurator"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Configurator = {}
|
||||
function shared.Configurator.Init()
|
||||
print("[Heimdall] Configurator module loaded")
|
||||
end
|
@@ -1,6 +1,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "DeathReporter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.DeathReporter = {}
|
||||
@@ -14,64 +15,104 @@ 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
|
||||
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))
|
||||
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
|
||||
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
|
||||
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())
|
||||
end
|
||||
|
||||
local text = string.format("%s killed %s with %s in %s",
|
||||
tostring(source),
|
||||
tostring(destination),
|
||||
tostring(spellName),
|
||||
tostring(zone))
|
||||
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.deathReporter.notifyChannel,
|
||||
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 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
|
||||
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] Cancelling delayed death report - Recent duel detected for: %s", ModuleName,
|
||||
source))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
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 = "C",
|
||||
data = channel,
|
||||
message = text
|
||||
}
|
||||
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,15 +120,33 @@ 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(...)
|
||||
if not err and overkill > 0 then
|
||||
local source, err = CLEUParser.GetSourceName(...)
|
||||
if err then source = "unknown" end
|
||||
if err then
|
||||
source = "unknown"
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Error getting source name", ModuleName))
|
||||
end
|
||||
end
|
||||
local destination, err = CLEUParser.GetDestName(...)
|
||||
if err then destination = "unknown" end
|
||||
if err then
|
||||
destination = "unknown"
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Error getting destination name", ModuleName))
|
||||
end
|
||||
end
|
||||
local spellName, err = CLEUParser.GetSpellName(...)
|
||||
if err then spellName = "unknown" end
|
||||
if err then
|
||||
spellName = "unknown"
|
||||
if Heimdall_Data.config.deathReporter.debug then
|
||||
print(string.format("[%s] Error getting spell name", ModuleName))
|
||||
end
|
||||
end
|
||||
local sourceGUID, err = CLEUParser.GetSourceGUID(...)
|
||||
if err or not string.match(sourceGUID, "Player") then return end
|
||||
local destinationGUID, err = CLEUParser.GetDestGUID(...)
|
||||
@@ -101,16 +160,26 @@ 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,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Dueler"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Dueler = {}
|
||||
@@ -8,18 +9,43 @@ 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,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Echoer"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Echoer = {}
|
||||
@@ -8,29 +9,53 @@ 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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
if channelname ~= Heimdall_Data.config.echoer.masterChannel then return end
|
||||
local channelId = select(6, ...)
|
||||
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 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
|
||||
if Heimdall_Data.config.echoer.debug then
|
||||
print(string.format("[%s] Found echo command in message: %s", ModuleName, msg))
|
||||
end
|
||||
local msg = 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, msg))
|
||||
end
|
||||
SendChatMessage(msg, "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,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Emoter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Emoter = {}
|
||||
@@ -8,28 +9,54 @@ 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,124 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Inviter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Inviter = {}
|
||||
function shared.Inviter.Init()
|
||||
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
|
||||
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Group configuration update complete", ModuleName))
|
||||
end
|
||||
end
|
||||
|
||||
local framePool = {}
|
||||
---@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()
|
||||
UninviteUnit(name)
|
||||
overlayButton:Hide()
|
||||
end)
|
||||
-- button:SetAttribute("type", "macro")
|
||||
-- button:SetAttribute("macrotext", "/kick " .. unit)
|
||||
return
|
||||
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
|
||||
local button = framePool[frame.unit] or CreateFrame("Button",
|
||||
string.format("HeimdallKickButton%s", frame.unit, frame, "SecureActionButtonTemplate"))
|
||||
framePool[frame.unit] = button
|
||||
|
||||
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)
|
||||
button:Hide()
|
||||
end)
|
||||
else
|
||||
if Heimdall_Data.config.inviter.debug then
|
||||
print(string.format("[%s] Frame for player %s not found", ModuleName, name))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -84,18 +149,21 @@ function shared.Inviter.Init()
|
||||
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()
|
||||
@@ -103,12 +171,23 @@ function shared.Inviter.Init()
|
||||
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 +195,55 @@ 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,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Macroer"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Macroer = {}
|
||||
@@ -11,22 +12,42 @@ 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 +56,13 @@ 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 +71,37 @@ 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")
|
||||
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,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Messenger"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Messenger = {}
|
||||
@@ -10,21 +11,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 +24,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 +35,103 @@ 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", ModuleName))
|
||||
--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 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
|
||||
message.channel = "CHANNEL"
|
||||
elseif string.find(message.channel, "^W") then
|
||||
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)
|
||||
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] Processing channel message: '%s' to '%s'", ModuleName, message.message,
|
||||
message.data))
|
||||
end
|
||||
local channelId = GetChannelName(message.data)
|
||||
if channelId == 0 then
|
||||
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
|
||||
-- local queueSize = #shared.messenger.queue
|
||||
-- print(string.format("[%s] Queue check - Messages pending: %d", ModuleName, queueSize))
|
||||
--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
|
||||
|
503
Modules/MinimapTagger.lua
Normal file
503
Modules/MinimapTagger.lua
Normal file
@@ -0,0 +1,503 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
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(self, 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
|
||||
---@param y number
|
||||
---@param scale number?
|
||||
---@param doTag boolean?
|
||||
local function PlantAlert(x, y, scale, doTag)
|
||||
if doTag == nil then doTag = true end
|
||||
local frame = nil
|
||||
for _, alertFrame in ipairs(alertFramePool) do
|
||||
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
|
||||
---@param y number
|
||||
---@param scale number?
|
||||
---@param doTag boolean?
|
||||
local function PlantTag(x, y, scale, doTag)
|
||||
if doTag == nil then doTag = true end
|
||||
local frame = nil
|
||||
for _, tagFrame in ipairs(tagFramePool) do
|
||||
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
|
||||
---@param y number
|
||||
---@param scale number?
|
||||
---@param doTag boolean?
|
||||
local function PlantCombat(x, y, scale, doTag)
|
||||
if doTag == nil then doTag = true end
|
||||
local frame = nil
|
||||
for _, combatFrame in ipairs(combatFramePool) do
|
||||
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
|
||||
---@param y number
|
||||
---@param scale number?
|
||||
---@param doTag boolean?
|
||||
local function PlantHelp(x, y, scale, doTag)
|
||||
if doTag == nil then doTag = true end
|
||||
local frame = nil
|
||||
for _, helpFrame in ipairs(helpFramePool) do
|
||||
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(self) self:StartMoving() end)
|
||||
BattlefieldMinimap:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
|
||||
BattlefieldMinimapBackground:Hide()
|
||||
BattlefieldMinimapCloseButton:Hide()
|
||||
BattlefieldMinimapCorner:Hide()
|
||||
BattlefieldMinimap:HookScript("OnHide", function(self)
|
||||
for _, alertFrame in ipairs(alertFramePool) do
|
||||
alertFrame:Hide()
|
||||
alertFrame.custom.busy = false
|
||||
end
|
||||
for _, tagFrame in ipairs(tagFramePool) do
|
||||
tagFrame:Hide()
|
||||
tagFrame.custom.busy = false
|
||||
end
|
||||
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)
|
||||
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
|
||||
|
||||
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"
|
76
Modules/Network.lua
Normal file
76
Modules/Network.lua
Normal file
@@ -0,0 +1,76 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
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, level, class, area, connected, status, note, RAF = 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 = {}
|
||||
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
|
178
Modules/NetworkMessenger.lua
Normal file
178
Modules/NetworkMessenger.lua
Normal file
@@ -0,0 +1,178 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
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 message = strtrim(tostring(parts[2]))
|
||||
local channel = 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, message, channel, target))
|
||||
end
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = channel,
|
||||
message = message,
|
||||
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 message = 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, message, recipient))
|
||||
end
|
||||
SendAddonMessage(Heimdall_Data.config.addonPrefix, message, "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
|
301
Modules/Noter.lua
Normal file
301
Modules/Noter.lua
Normal file
@@ -0,0 +1,301 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
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
|
90
Modules/Sniffer.lua
Normal file
90
Modules/Sniffer.lua
Normal file
@@ -0,0 +1,90 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
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, 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)
|
||||
local 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,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Spotter"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Spotter = {}
|
||||
@@ -27,15 +28,47 @@ 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 +76,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 +108,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",
|
||||
name,
|
||||
class,
|
||||
stinky and string.format("(%s)", "!!!!") or "",
|
||||
race,
|
||||
faction,
|
||||
FormatHP(hp),
|
||||
FormatHP(maxHp),
|
||||
location,
|
||||
x * 100, y * 100)
|
||||
if Heimdall_Data.config.spotter.debug then
|
||||
print(string.format("[%s] Player %s coordinates: %.2f, %.2f", ModuleName, name, x * 100, y * 100))
|
||||
end
|
||||
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.spotter.notifyChannel,
|
||||
message = text
|
||||
}
|
||||
--shared.dumpTable(msg)
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
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,
|
||||
shared._L(class, locale),
|
||||
stinky and string.format("(%s)", "!!!!") or "",
|
||||
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 = "C",
|
||||
data = channel,
|
||||
message = text
|
||||
}
|
||||
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 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
|
||||
|
60
Modules/StinkyCache.lua
Normal file
60
Modules/StinkyCache.lua
Normal file
@@ -0,0 +1,60 @@
|
||||
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 name, value = {strsplit("|", msg)}
|
||||
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,6 +1,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "StinkyTracker"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.StinkyTracker = {}
|
||||
@@ -13,6 +14,9 @@ function shared.StinkyTracker.Init()
|
||||
---@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] = {
|
||||
@@ -21,38 +25,62 @@ function shared.StinkyTracker.Init()
|
||||
seenAt = GetTime(),
|
||||
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 = {
|
||||
@@ -62,48 +90,172 @@ function shared.StinkyTracker.Init()
|
||||
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
|
||||
end
|
||||
if string.find(msg, " and guild ") then
|
||||
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
|
||||
local 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,7 @@
|
||||
local addonname, shared = ...
|
||||
---@cast shared HeimdallShared
|
||||
---@cast addonname string
|
||||
local ModuleName = "Whoer"
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
shared.Whoer = {}
|
||||
@@ -55,22 +56,6 @@ function shared.Whoer.Init()
|
||||
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
|
||||
@@ -90,75 +75,227 @@ function shared.Whoer.Init()
|
||||
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
|
||||
return zone ~= "Siege of Orgrimmar"
|
||||
end
|
||||
---@type WHOFilter
|
||||
local AllianceFilter = 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
|
||||
|
||||
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", {})
|
||||
local NotSiegeOfOrgrimmarFilter = {
|
||||
Run = function(name, guild, level, race, class, zone)
|
||||
if not zone then
|
||||
return false
|
||||
end
|
||||
return zone ~= "Siege of Orgrimmar"
|
||||
end,
|
||||
key = "notsoo"
|
||||
}
|
||||
local ttl = #whoQueries * 2
|
||||
---@type WHOFilter
|
||||
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
|
||||
|
||||
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 queries string
|
||||
---@return WHOQuery[]
|
||||
WhoQueriesFromString = function(queries)
|
||||
local queries = shared.Split(queries, "\n")
|
||||
local ret = {}
|
||||
for _, query in pairs(queries) do
|
||||
table.insert(ret, shared.WhoQueryService.WhoQueryFromString(query))
|
||||
end
|
||||
return ret
|
||||
end
|
||||
}
|
||||
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 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))
|
||||
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 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)
|
||||
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 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 = "C",
|
||||
data = channel,
|
||||
message = text
|
||||
}
|
||||
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,38 +304,48 @@ 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",
|
||||
player.name,
|
||||
player.class,
|
||||
player.race,
|
||||
shared.raceMap[player.race] or "Unknown",
|
||||
player.guild,
|
||||
zone)
|
||||
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.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(zone, locale))
|
||||
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "CHANNEL",
|
||||
data = Heimdall_Data.config.who.notifyChannel,
|
||||
message = text
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
|
||||
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)
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text
|
||||
}
|
||||
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 = "W",
|
||||
-- data = name,
|
||||
-- message = text
|
||||
-- }
|
||||
-- --table.insert(shared.messenger.queue, msg)
|
||||
-- table.insert(shared.networkMessenger.queue, msg)
|
||||
-- end
|
||||
--end
|
||||
|
||||
return nil
|
||||
end
|
||||
---@param player Player
|
||||
@@ -206,88 +353,148 @@ 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",
|
||||
player.name,
|
||||
player.class,
|
||||
player.guild,
|
||||
player.zone)
|
||||
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.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 = "CHANNEL",
|
||||
data = Heimdall_Data.config.who.notifyChannel,
|
||||
message = text
|
||||
}
|
||||
table.insert(shared.messenger.queue, msg)
|
||||
|
||||
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)
|
||||
---@type Message
|
||||
local msg = {
|
||||
channel = "C",
|
||||
data = channel,
|
||||
message = text
|
||||
}
|
||||
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 = "W",
|
||||
-- data = name,
|
||||
-- message = text
|
||||
-- }
|
||||
-- --table.insert(shared.messenger.queue, msg)
|
||||
-- table.insert(shared.networkMessenger.queue, msg)
|
||||
-- end
|
||||
--end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
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))
|
||||
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
|
||||
else
|
||||
if Heimdall_Data.config.who.debug then
|
||||
print(string.format("[%s] Player %s is not blacklisted", ModuleName, name))
|
||||
end
|
||||
end
|
||||
if Heimdall_Data.config.who.ignored[name] then continue = true end
|
||||
--print(continue)
|
||||
|
||||
if not continue then
|
||||
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
|
||||
@@ -296,7 +503,7 @@ function shared.Whoer.Init()
|
||||
|
||||
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,6 +513,10 @@ function shared.Whoer.Init()
|
||||
|
||||
player.lastSeenInternal = GetTime()
|
||||
if player.zone ~= zone then
|
||||
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)))
|
||||
@@ -345,9 +556,15 @@ function shared.Whoer.Init()
|
||||
local function DoQuery()
|
||||
if not Heimdall_Data.config.who.enabled then return end
|
||||
|
||||
local query = whoQueries[whoQueryIdx]
|
||||
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", ModuleName))
|
||||
end
|
||||
return
|
||||
end
|
||||
whoQueryIdx = whoQueryIdx + 1
|
||||
if whoQueryIdx > #whoQueries then
|
||||
if whoQueryIdx > #shared.WhoQueryService.queries then
|
||||
whoQueryIdx = 1
|
||||
end
|
||||
lastQuery = query
|
||||
@@ -363,5 +580,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.
BIN
Texture/Aura21.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura21.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura22.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura22.tga
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Texture/Aura23.tga
(Stored with Git LFS)
Normal file
BIN
Texture/Aura23.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