Refactor Heimdall modules to improve structure and clarity, including AchievementSniffer, BonkDetector, Bully, Commander, and Config.
This commit is contained in:
		
							
								
								
									
										70
									
								
								Heimdall.lua
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								Heimdall.lua
									
									
									
									
									
								
							@@ -36,30 +36,30 @@ local function init()
 | 
			
		||||
	---@field Memoize fun(f: function): function
 | 
			
		||||
	---@field GetLocaleForChannel fun(channel: string): string
 | 
			
		||||
	---@field WhoQueryService WhoQueryService
 | 
			
		||||
	---@field Whoer InitTable|{ShouldNotifyForZone: fun(zone: string): boolean}
 | 
			
		||||
	---@field AchievementSniffer InitTable
 | 
			
		||||
	---@field AchievementSniffer AchievementSniffer
 | 
			
		||||
	---@field AgentTracker AgentTracker
 | 
			
		||||
	---@field BonkDetector InitTable
 | 
			
		||||
	---@field Bully InitTable
 | 
			
		||||
	---@field CombatAlerter InitTable
 | 
			
		||||
	---@field Commander InitTable
 | 
			
		||||
	---@field Config InitTable
 | 
			
		||||
	---@field Configurator InitTable
 | 
			
		||||
	---@field DeathReporter InitTable
 | 
			
		||||
	---@field Dueler InitTable
 | 
			
		||||
	---@field Echoer InitTable
 | 
			
		||||
	---@field Emoter InitTable
 | 
			
		||||
	---@field Inviter InitTable
 | 
			
		||||
	---@field Macroer InitTable
 | 
			
		||||
	---@field Messenger InitTable
 | 
			
		||||
	---@field MinimapTagger InitTable
 | 
			
		||||
	---@field Network InitTable
 | 
			
		||||
	---@field NetworkMessenger InitTable
 | 
			
		||||
	---@field Noter InitTable
 | 
			
		||||
	---@field Sniffer InitTable
 | 
			
		||||
	---@field Spotter InitTable
 | 
			
		||||
	---@field StinkyCache InitTable
 | 
			
		||||
	---@field BonkDetector BonkDetector
 | 
			
		||||
	---@field Bully Bully
 | 
			
		||||
	---@field CombatAlerter CombatAlerter
 | 
			
		||||
	---@field Commander Commander
 | 
			
		||||
	---@field Config Config
 | 
			
		||||
	---@field Configurator Configurator
 | 
			
		||||
	---@field DeathReporter DeathReporter
 | 
			
		||||
	---@field Dueler Dueler
 | 
			
		||||
	---@field Echoer Echoer
 | 
			
		||||
	---@field Emoter Emoter
 | 
			
		||||
	---@field Inviter Inviter
 | 
			
		||||
	---@field Macroer Macroer
 | 
			
		||||
	---@field Messenger Messenger
 | 
			
		||||
	---@field MinimapTagger MinimapTagger
 | 
			
		||||
	---@field Network Network
 | 
			
		||||
	---@field NetworkMessenger NetworkMessenger
 | 
			
		||||
	---@field Noter Noter
 | 
			
		||||
	---@field Sniffer Sniffer
 | 
			
		||||
	---@field Spotter Spotter
 | 
			
		||||
	---@field StinkyCache StinkyCache
 | 
			
		||||
	---@field StinkyTracker StinkyTracker
 | 
			
		||||
	---@field Whoer Whoer
 | 
			
		||||
 | 
			
		||||
	--- Config ---
 | 
			
		||||
	---@class HeimdallConfig
 | 
			
		||||
@@ -119,19 +119,6 @@ local function init()
 | 
			
		||||
	---@field debug boolean
 | 
			
		||||
	---@field interval number
 | 
			
		||||
 | 
			
		||||
	---@class HeimdallInviterConfig
 | 
			
		||||
	---@field enabled boolean
 | 
			
		||||
	---@field debug boolean
 | 
			
		||||
	---@field channels string[]
 | 
			
		||||
	---@field keyword string
 | 
			
		||||
	---@field allAssist boolean
 | 
			
		||||
	---@field agentsAssist boolean
 | 
			
		||||
	---@field throttle number
 | 
			
		||||
	---@field kickOffline boolean
 | 
			
		||||
	---@field cleanupInterval number
 | 
			
		||||
	---@field afkThreshold number
 | 
			
		||||
	---@field listeningChannel table<string, boolean>
 | 
			
		||||
 | 
			
		||||
	---@class HeimdallDuelerConfig
 | 
			
		||||
	---@field enabled boolean
 | 
			
		||||
	---@field debug boolean
 | 
			
		||||
@@ -149,25 +136,12 @@ local function init()
 | 
			
		||||
	---@field channels string[]
 | 
			
		||||
	---@field prefix string
 | 
			
		||||
 | 
			
		||||
	---@class HeimdallMacroerConfig
 | 
			
		||||
	---@field enabled boolean
 | 
			
		||||
	---@field debug boolean
 | 
			
		||||
	---@field priority string[]
 | 
			
		||||
 | 
			
		||||
	---@class HeimdallStinkyTrackerConfig
 | 
			
		||||
	---@field enabled boolean
 | 
			
		||||
	---@field debug boolean
 | 
			
		||||
	---@field ignoredTimeout number
 | 
			
		||||
	---@field channels string[]
 | 
			
		||||
 | 
			
		||||
	---@class HeimdallSnifferConfig
 | 
			
		||||
	---@field enabled boolean
 | 
			
		||||
	---@field debug boolean
 | 
			
		||||
	---@field channels string[]
 | 
			
		||||
	---@field throttle number
 | 
			
		||||
	---@field zoneOverride string?
 | 
			
		||||
	---@field stinky boolean
 | 
			
		||||
 | 
			
		||||
	---@class HeimdallMinimapTaggerConfig
 | 
			
		||||
	---@field enabled boolean
 | 
			
		||||
	---@field debug boolean
 | 
			
		||||
 
 | 
			
		||||
@@ -74,220 +74,221 @@ local Achievements = {
 | 
			
		||||
	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)
 | 
			
		||||
---@class AchievementSniffer
 | 
			
		||||
shared.AchievementSniffer = {
 | 
			
		||||
	Init = function()
 | 
			
		||||
		if Heimdall_Data.config.achievementSniffer.debug then
 | 
			
		||||
			print(string.format("[%s] Scanning achievements for %s", ModuleName, name))
 | 
			
		||||
			print(string.format("[%s] Module initialized", ModuleName))
 | 
			
		||||
		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 guidMap = {}
 | 
			
		||||
 | 
			
		||||
				local date = string.format("%04d-%02d-%02d", yearstr, month, day)
 | 
			
		||||
		---@class AchievementData
 | 
			
		||||
		---@field id number
 | 
			
		||||
		---@field date string
 | 
			
		||||
		---@field completed boolean
 | 
			
		||||
 | 
			
		||||
				local data = {
 | 
			
		||||
					id = aid,
 | 
			
		||||
					date = date,
 | 
			
		||||
					completed = completed,
 | 
			
		||||
				}
 | 
			
		||||
		---@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] Achievement %d completed on %s", ModuleName, aid, date))
 | 
			
		||||
					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
 | 
			
		||||
				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
 | 
			
		||||
		---@param name string
 | 
			
		||||
		local function Scan(name)
 | 
			
		||||
			if Heimdall_Data.config.achievementSniffer.debug then
 | 
			
		||||
				print(string.format("[%s] No name found for guid: %s", ModuleName, guid))
 | 
			
		||||
				print(string.format("[%s] Scanning achievements for %s", ModuleName, name))
 | 
			
		||||
			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)
 | 
			
		||||
			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 function Tick()
 | 
			
		||||
		C_Timer.NewTimer(Heimdall_Data.config.achievementSniffer.scanInterval, Tick)
 | 
			
		||||
		if not Heimdall_Data.config.achievementSniffer.enabled then return end
 | 
			
		||||
					local date = string.format("%04d-%02d-%02d", yearstr, month, day)
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
					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
 | 
			
		||||
		--UpdateFrames()
 | 
			
		||||
	end
 | 
			
		||||
	Tick()
 | 
			
		||||
 | 
			
		||||
	print("[Heimdall] AchievementSniffer loaded")
 | 
			
		||||
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,5 +1,6 @@
 | 
			
		||||
local _, shared = ...
 | 
			
		||||
---@cast shared HeimdallShared
 | 
			
		||||
local ModuleName = "BonkDetector"
 | 
			
		||||
 | 
			
		||||
---@class HeimdallBonkDetectorConfig
 | 
			
		||||
---@field enabled boolean
 | 
			
		||||
@@ -7,8 +8,7 @@ local _, shared = ...
 | 
			
		||||
---@field channels string[]
 | 
			
		||||
---@field throttle number
 | 
			
		||||
 | 
			
		||||
local ModuleName = "BonkDetector"
 | 
			
		||||
 | 
			
		||||
---@class BonkDetector
 | 
			
		||||
shared.BonkDetector = {
 | 
			
		||||
	---@return nil
 | 
			
		||||
	Init = function()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
local _, shared = ...
 | 
			
		||||
---@cast shared HeimdallShared
 | 
			
		||||
local ModuleName = "Bully"
 | 
			
		||||
 | 
			
		||||
---@class HeimdallBullyConfig
 | 
			
		||||
---@field enabled boolean
 | 
			
		||||
---@field debug boolean
 | 
			
		||||
 | 
			
		||||
local ModuleName = "Bully"
 | 
			
		||||
 | 
			
		||||
---@class Bully
 | 
			
		||||
shared.Bully = {
 | 
			
		||||
	---@return nil
 | 
			
		||||
	Init = function()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,394 +1,389 @@
 | 
			
		||||
local _, shared = ...
 | 
			
		||||
---@cast shared HeimdallShared
 | 
			
		||||
 | 
			
		||||
---@class HeimdallCommanderConfig
 | 
			
		||||
---@field enabled boolean
 | 
			
		||||
---@field debug boolean
 | 
			
		||||
---@field channels string[]
 | 
			
		||||
---@field commander string
 | 
			
		||||
---@field commands table<string, boolean>
 | 
			
		||||
 | 
			
		||||
local ModuleName = "Commander"
 | 
			
		||||
 | 
			
		||||
local helpMessages = {
 | 
			
		||||
	ru = {
 | 
			
		||||
		"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",
 | 
			
		||||
		"2) classes - reports stinkies grouped by class",
 | 
			
		||||
		"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.",
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
---@class Commander
 | 
			
		||||
shared.Commander = {
 | 
			
		||||
	Init = function()
 | 
			
		||||
		---@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 arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function Count(arr)
 | 
			
		||||
			local ret = {}
 | 
			
		||||
			for _, player in pairs(arr) do
 | 
			
		||||
				if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.zone] = (ret[player.zone] or 0) + 1 end
 | 
			
		||||
			end
 | 
			
		||||
			local text = {}
 | 
			
		||||
			for zone, count in pairs(ret) do
 | 
			
		||||
				text[#text + 1] = string.format("%s: %d", zone, count)
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		---@param arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function CountPartitioned(arr)
 | 
			
		||||
			local count = Count(arr)
 | 
			
		||||
			local text = {}
 | 
			
		||||
			---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
			for _, line in pairs(Partition(strjoin(", ", unpack(count)), 200)) do
 | 
			
		||||
				text[#text + 1] = line
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		---@param arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function Who(arr)
 | 
			
		||||
			local ret = {}
 | 
			
		||||
			for _, player in pairs(arr) do
 | 
			
		||||
				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>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function WhoPartitioned(arr)
 | 
			
		||||
			local who = Who(arr)
 | 
			
		||||
			local text = {}
 | 
			
		||||
			---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
			for _, line in pairs(Partition(strjoin(", ", unpack(who)), 200)) do
 | 
			
		||||
				text[#text + 1] = "who: " .. line
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		---@param arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function CountClass(arr)
 | 
			
		||||
			local ret = {}
 | 
			
		||||
			for _, player in pairs(arr) do
 | 
			
		||||
				if shared.Whoer.ShouldNotifyForZone(player.zone) then
 | 
			
		||||
					ret[player.class] = (ret[player.class] or 0) + 1
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			local text = {}
 | 
			
		||||
			for class, count in pairs(ret) do
 | 
			
		||||
				text[#text + 1] = string.format("%s: %d", class, count)
 | 
			
		||||
			end
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] Message text: %s", ModuleName, strjoin(", ", unpack(text))))
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		---@param arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function CountClassPartitioned(arr)
 | 
			
		||||
			local countClass = CountClass(arr)
 | 
			
		||||
			local text = {}
 | 
			
		||||
			---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
			for _, line in pairs(Partition(strjoin(", ", unpack(countClass)), 200)) do
 | 
			
		||||
				text[#text + 1] = line
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		local function CountClassPartitionedStinkies()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] Executing: CountClassPartitionedStinkies", ModuleName))
 | 
			
		||||
			end
 | 
			
		||||
			local res = CountClassPartitioned(HeimdallStinkies)
 | 
			
		||||
			if #res == 0 then return { "No stinkies found" } end
 | 
			
		||||
			return res
 | 
			
		||||
		end
 | 
			
		||||
		local function WhoPartitionedStinkies()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] Executing: WhoPartitionedStinkies", ModuleName))
 | 
			
		||||
				shared.dumpTable(HeimdallStinkies)
 | 
			
		||||
			end
 | 
			
		||||
			local res = WhoPartitioned(HeimdallStinkies)
 | 
			
		||||
			if #res == 0 then return { "No stinkies found" } end
 | 
			
		||||
			return res
 | 
			
		||||
		end
 | 
			
		||||
		local function CountPartitionedStinkies()
 | 
			
		||||
			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()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpRu", ModuleName)) end
 | 
			
		||||
			return helpMessages.ru
 | 
			
		||||
		end
 | 
			
		||||
		local function HelpEn()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpEn", ModuleName)) end
 | 
			
		||||
			return helpMessages.en
 | 
			
		||||
		end
 | 
			
		||||
		local groupInviteFrame = CreateFrame("Frame")
 | 
			
		||||
		groupInviteFrame:SetScript("OnEvent", function(self, event, ...)
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then print(string.format("[%s] Event received", ModuleName)) end
 | 
			
		||||
			AcceptGroup()
 | 
			
		||||
			groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST")
 | 
			
		||||
			C_Timer.NewTimer(0.1, function()
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Click event triggered", ModuleName))
 | 
			
		||||
				end
 | 
			
		||||
				_G["StaticPopup1Button1"]:Click()
 | 
			
		||||
			end, 1)
 | 
			
		||||
		end)
 | 
			
		||||
		local function JoinGroup()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] JoinGroup command received", ModuleName))
 | 
			
		||||
			end
 | 
			
		||||
			groupInviteFrame:RegisterEvent("PARTY_INVITE_REQUEST")
 | 
			
		||||
			C_Timer.NewTimer(10, function() groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") end, 1)
 | 
			
		||||
			return { "+" }
 | 
			
		||||
		end
 | 
			
		||||
		local function LeaveGroup()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] LeaveGroup command received", ModuleName))
 | 
			
		||||
			end
 | 
			
		||||
			LeaveParty()
 | 
			
		||||
			return {}
 | 
			
		||||
		end
 | 
			
		||||
		---@param target string
 | 
			
		||||
		local function FollowTarget(target)
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] Following target: %s", ModuleName, target))
 | 
			
		||||
			end
 | 
			
		||||
			if not target then return end
 | 
			
		||||
			FollowUnit(target)
 | 
			
		||||
			return {}
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		---@param args string[]
 | 
			
		||||
		local function MacroTarget(args)
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
				print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args))))
 | 
			
		||||
			end
 | 
			
		||||
			if #args < 2 or #args % 2 ~= 0 then
 | 
			
		||||
				if #args < 2 or #args % 2 ~= 0 then
 | 
			
		||||
					if Heimdall_Data.config.commander.debug then
 | 
			
		||||
						print(string.format("[%s] Invalid number of arguments for MacroTarget", ModuleName))
 | 
			
		||||
					end
 | 
			
		||||
					return {}
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			table.remove(args, 1)
 | 
			
		||||
 | 
			
		||||
			for i = 1, #args do
 | 
			
		||||
				local stinky = strtrim(args[i])
 | 
			
		||||
				local name = stinky:match("([^/]+)")
 | 
			
		||||
				local class = stinky:match("/([^ $]+)")
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Adding stinky: %s/%s", ModuleName, name, tostring(class)))
 | 
			
		||||
				end
 | 
			
		||||
				shared.StinkyTracker.Track({
 | 
			
		||||
					name = name,
 | 
			
		||||
					class = class or "unknown",
 | 
			
		||||
					seenAt = GetTime(),
 | 
			
		||||
					hostile = true,
 | 
			
		||||
				})
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Added stinky: %s/%s", ModuleName, name, tostring(class)))
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			return {}
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		---@param args string[]
 | 
			
		||||
		local function IgnoreMacroTarget(args)
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
				print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args))))
 | 
			
		||||
			end
 | 
			
		||||
			if #args < 1 then
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Invalid number of arguments for IgnoreMacroTarget", ModuleName))
 | 
			
		||||
				end
 | 
			
		||||
				return {}
 | 
			
		||||
			end
 | 
			
		||||
			table.remove(args, 1)
 | 
			
		||||
 | 
			
		||||
			for i = 1, #args do
 | 
			
		||||
				local stinky = strtrim(args[i])
 | 
			
		||||
				local name = stinky:match("([^/]+)")
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Ignoring stinky: %s", ModuleName, name))
 | 
			
		||||
				end
 | 
			
		||||
				shared.StinkyTracker.Ignore(name)
 | 
			
		||||
			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 = "^macro", commanderOnly = false, callback = MacroTarget },
 | 
			
		||||
			{ keywordRe = "^ignore", commanderOnly = false, callback = IgnoreMacroTarget },
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		local commanderChannelFrame = CreateFrame("Frame")
 | 
			
		||||
		commanderChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL")
 | 
			
		||||
		commanderChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
 | 
			
		||||
			--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)
 | 
			
		||||
			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
 | 
			
		||||
						-- if Heimdall_Data.config.commander.debug then print(string.format("[%s] Ignoring command, sender %s not commander %s", ModuleName, sender, Heimdall_Data.config.commander.commander)) end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
						or (command.commanderOnly and sender == Heimdall_Data.config.commander.commander)
 | 
			
		||||
					)
 | 
			
		||||
				then
 | 
			
		||||
					if msg:match(command.keywordRe) then
 | 
			
		||||
						---@diagnostic disable-next-line: redundant-parameter Currently luals does not support variadic functions as a @field
 | 
			
		||||
						local messages = command.callback({ strsplit(",", msg) })
 | 
			
		||||
						if Heimdall_Data.config.commander.debug then
 | 
			
		||||
							---@diagnostic disable-next-line: param-type-mismatch
 | 
			
		||||
							print(
 | 
			
		||||
								string.format("[%s] Messages to send: %s", ModuleName, strjoin(", ", unpack(messages)))
 | 
			
		||||
							)
 | 
			
		||||
						end
 | 
			
		||||
						for _, message in ipairs(messages) do
 | 
			
		||||
							---@type Message
 | 
			
		||||
							local returnmsg = {
 | 
			
		||||
								channel = "C",
 | 
			
		||||
								data = channelname,
 | 
			
		||||
								message = message,
 | 
			
		||||
							}
 | 
			
		||||
							if Heimdall_Data.config.commander.debug then
 | 
			
		||||
								print(string.format("[%s] Queuing message", ModuleName))
 | 
			
		||||
								shared.dumpTable(msg)
 | 
			
		||||
							end
 | 
			
		||||
							--table.insert(shared.messenger.queue, msg)
 | 
			
		||||
							table.insert(shared.networkMessenger.queue, returnmsg)
 | 
			
		||||
						end
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
 | 
			
		||||
		print("[Heimdall] Commander module loaded")
 | 
			
		||||
	end,
 | 
			
		||||
}
 | 
			
		||||
local _, shared = ...
 | 
			
		||||
---@cast shared HeimdallShared
 | 
			
		||||
local ModuleName = "Commander"
 | 
			
		||||
 | 
			
		||||
---@class HeimdallCommanderConfig
 | 
			
		||||
---@field enabled boolean
 | 
			
		||||
---@field debug boolean
 | 
			
		||||
---@field channels string[]
 | 
			
		||||
---@field commander string
 | 
			
		||||
---@field commands table<string, boolean>
 | 
			
		||||
 | 
			
		||||
local helpMessages = {
 | 
			
		||||
	ru = {
 | 
			
		||||
		"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",
 | 
			
		||||
		"2) classes - reports stinkies grouped by class",
 | 
			
		||||
		"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.",
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
---@class Commander
 | 
			
		||||
shared.Commander = {
 | 
			
		||||
	Init = function()
 | 
			
		||||
		---@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 arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function Count(arr)
 | 
			
		||||
			local ret = {}
 | 
			
		||||
			for _, player in pairs(arr) do
 | 
			
		||||
				if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.zone] = (ret[player.zone] or 0) + 1 end
 | 
			
		||||
			end
 | 
			
		||||
			local text = {}
 | 
			
		||||
			for zone, count in pairs(ret) do
 | 
			
		||||
				text[#text + 1] = string.format("%s: %d", zone, count)
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		---@param arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function CountPartitioned(arr)
 | 
			
		||||
			local count = Count(arr)
 | 
			
		||||
			local text = {}
 | 
			
		||||
			---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
			for _, line in pairs(Partition(strjoin(", ", unpack(count)), 200)) do
 | 
			
		||||
				text[#text + 1] = line
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		---@param arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function Who(arr)
 | 
			
		||||
			local ret = {}
 | 
			
		||||
			for _, player in pairs(arr) do
 | 
			
		||||
				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>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function WhoPartitioned(arr)
 | 
			
		||||
			local who = Who(arr)
 | 
			
		||||
			local text = {}
 | 
			
		||||
			---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
			for _, line in pairs(Partition(strjoin(", ", unpack(who)), 200)) do
 | 
			
		||||
				text[#text + 1] = "who: " .. line
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		---@param arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function CountClass(arr)
 | 
			
		||||
			local ret = {}
 | 
			
		||||
			for _, player in pairs(arr) do
 | 
			
		||||
				if shared.Whoer.ShouldNotifyForZone(player.zone) then
 | 
			
		||||
					ret[player.class] = (ret[player.class] or 0) + 1
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			local text = {}
 | 
			
		||||
			for class, count in pairs(ret) do
 | 
			
		||||
				text[#text + 1] = string.format("%s: %d", class, count)
 | 
			
		||||
			end
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] Message text: %s", ModuleName, strjoin(", ", unpack(text))))
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		---@param arr table<string, Player>
 | 
			
		||||
		---@return string[]
 | 
			
		||||
		local function CountClassPartitioned(arr)
 | 
			
		||||
			local countClass = CountClass(arr)
 | 
			
		||||
			local text = {}
 | 
			
		||||
			---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
			for _, line in pairs(Partition(strjoin(", ", unpack(countClass)), 200)) do
 | 
			
		||||
				text[#text + 1] = line
 | 
			
		||||
			end
 | 
			
		||||
			return text
 | 
			
		||||
		end
 | 
			
		||||
		local function CountClassPartitionedStinkies()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] Executing: CountClassPartitionedStinkies", ModuleName))
 | 
			
		||||
			end
 | 
			
		||||
			local res = CountClassPartitioned(HeimdallStinkies)
 | 
			
		||||
			if #res == 0 then return { "No stinkies found" } end
 | 
			
		||||
			return res
 | 
			
		||||
		end
 | 
			
		||||
		local function WhoPartitionedStinkies()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] Executing: WhoPartitionedStinkies", ModuleName))
 | 
			
		||||
				shared.dumpTable(HeimdallStinkies)
 | 
			
		||||
			end
 | 
			
		||||
			local res = WhoPartitioned(HeimdallStinkies)
 | 
			
		||||
			if #res == 0 then return { "No stinkies found" } end
 | 
			
		||||
			return res
 | 
			
		||||
		end
 | 
			
		||||
		local function CountPartitionedStinkies()
 | 
			
		||||
			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()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpRu", ModuleName)) end
 | 
			
		||||
			return helpMessages.ru
 | 
			
		||||
		end
 | 
			
		||||
		local function HelpEn()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpEn", ModuleName)) end
 | 
			
		||||
			return helpMessages.en
 | 
			
		||||
		end
 | 
			
		||||
		local groupInviteFrame = CreateFrame("Frame")
 | 
			
		||||
		groupInviteFrame:SetScript("OnEvent", function(self, event, ...)
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then print(string.format("[%s] Event received", ModuleName)) end
 | 
			
		||||
			AcceptGroup()
 | 
			
		||||
			groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST")
 | 
			
		||||
			C_Timer.NewTimer(0.1, function()
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Click event triggered", ModuleName))
 | 
			
		||||
				end
 | 
			
		||||
				_G["StaticPopup1Button1"]:Click()
 | 
			
		||||
			end, 1)
 | 
			
		||||
		end)
 | 
			
		||||
		local function JoinGroup()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] JoinGroup command received", ModuleName))
 | 
			
		||||
			end
 | 
			
		||||
			groupInviteFrame:RegisterEvent("PARTY_INVITE_REQUEST")
 | 
			
		||||
			C_Timer.NewTimer(10, function() groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") end, 1)
 | 
			
		||||
			return { "+" }
 | 
			
		||||
		end
 | 
			
		||||
		local function LeaveGroup()
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] LeaveGroup command received", ModuleName))
 | 
			
		||||
			end
 | 
			
		||||
			LeaveParty()
 | 
			
		||||
			return {}
 | 
			
		||||
		end
 | 
			
		||||
		---@param target string
 | 
			
		||||
		local function FollowTarget(target)
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				print(string.format("[%s] Following target: %s", ModuleName, target))
 | 
			
		||||
			end
 | 
			
		||||
			if not target then return end
 | 
			
		||||
			FollowUnit(target)
 | 
			
		||||
			return {}
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		---@param args string[]
 | 
			
		||||
		local function MacroTarget(args)
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
				print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args))))
 | 
			
		||||
			end
 | 
			
		||||
			if #args < 2 or #args % 2 ~= 0 then
 | 
			
		||||
				if #args < 2 or #args % 2 ~= 0 then
 | 
			
		||||
					if Heimdall_Data.config.commander.debug then
 | 
			
		||||
						print(string.format("[%s] Invalid number of arguments for MacroTarget", ModuleName))
 | 
			
		||||
					end
 | 
			
		||||
					return {}
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			table.remove(args, 1)
 | 
			
		||||
 | 
			
		||||
			for i = 1, #args do
 | 
			
		||||
				local stinky = strtrim(args[i])
 | 
			
		||||
				local name = stinky:match("([^/]+)")
 | 
			
		||||
				local class = stinky:match("/([^ $]+)")
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Adding stinky: %s/%s", ModuleName, name, tostring(class)))
 | 
			
		||||
				end
 | 
			
		||||
				shared.StinkyTracker.Track({
 | 
			
		||||
					name = name,
 | 
			
		||||
					class = class or "unknown",
 | 
			
		||||
					seenAt = GetTime(),
 | 
			
		||||
					hostile = true,
 | 
			
		||||
				})
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Added stinky: %s/%s", ModuleName, name, tostring(class)))
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			return {}
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		---@param args string[]
 | 
			
		||||
		local function IgnoreMacroTarget(args)
 | 
			
		||||
			if Heimdall_Data.config.commander.debug then
 | 
			
		||||
				---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
 | 
			
		||||
				print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args))))
 | 
			
		||||
			end
 | 
			
		||||
			if #args < 1 then
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Invalid number of arguments for IgnoreMacroTarget", ModuleName))
 | 
			
		||||
				end
 | 
			
		||||
				return {}
 | 
			
		||||
			end
 | 
			
		||||
			table.remove(args, 1)
 | 
			
		||||
 | 
			
		||||
			for i = 1, #args do
 | 
			
		||||
				local stinky = strtrim(args[i])
 | 
			
		||||
				local name = stinky:match("([^/]+)")
 | 
			
		||||
				if Heimdall_Data.config.commander.debug then
 | 
			
		||||
					print(string.format("[%s] Ignoring stinky: %s", ModuleName, name))
 | 
			
		||||
				end
 | 
			
		||||
				shared.StinkyTracker.Ignore(name)
 | 
			
		||||
			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 = "^macro", commanderOnly = false, callback = MacroTarget },
 | 
			
		||||
			{ keywordRe = "^ignore", commanderOnly = false, callback = IgnoreMacroTarget },
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		local commanderChannelFrame = CreateFrame("Frame")
 | 
			
		||||
		commanderChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL")
 | 
			
		||||
		commanderChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
 | 
			
		||||
			--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)
 | 
			
		||||
			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
 | 
			
		||||
						-- if Heimdall_Data.config.commander.debug then print(string.format("[%s] Ignoring command, sender %s not commander %s", ModuleName, sender, Heimdall_Data.config.commander.commander)) end
 | 
			
		||||
 | 
			
		||||
						or (command.commanderOnly and sender == Heimdall_Data.config.commander.commander)
 | 
			
		||||
					)
 | 
			
		||||
				then
 | 
			
		||||
					if msg:match(command.keywordRe) then
 | 
			
		||||
						---@diagnostic disable-next-line: redundant-parameter Currently luals does not support variadic functions as a @field
 | 
			
		||||
						local messages = command.callback({ strsplit(",", msg) })
 | 
			
		||||
						if Heimdall_Data.config.commander.debug then
 | 
			
		||||
							---@diagnostic disable-next-line: param-type-mismatch
 | 
			
		||||
							print(
 | 
			
		||||
								string.format("[%s] Messages to send: %s", ModuleName, strjoin(", ", unpack(messages)))
 | 
			
		||||
							)
 | 
			
		||||
						end
 | 
			
		||||
						for _, message in ipairs(messages) do
 | 
			
		||||
							---@type Message
 | 
			
		||||
							local returnmsg = {
 | 
			
		||||
								channel = "C",
 | 
			
		||||
								data = channelname,
 | 
			
		||||
								message = message,
 | 
			
		||||
							}
 | 
			
		||||
							if Heimdall_Data.config.commander.debug then
 | 
			
		||||
								print(string.format("[%s] Queuing message", ModuleName))
 | 
			
		||||
								shared.dumpTable(msg)
 | 
			
		||||
							end
 | 
			
		||||
							--table.insert(shared.messenger.queue, msg)
 | 
			
		||||
							table.insert(shared.networkMessenger.queue, returnmsg)
 | 
			
		||||
						end
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
 | 
			
		||||
		print("[Heimdall] Commander module loaded")
 | 
			
		||||
	end,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4309
									
								
								Modules/Config.lua
									
									
									
									
									
								
							
							
						
						
									
										4309
									
								
								Modules/Config.lua
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user