Quantcast
-- __________ Master Looter Assistant by Niketa-Moonrunner (US) / http://niketa.net / addons@niketa.net __________ --

-- __________ NAMESPACE __________ --
local M = MLA_Namespace

-- __________ LOCALIZATION __________ --
local L = M.Localization

-- __________ INITIALIZATION __________ --
local events = CreateFrame("Frame")

events:RegisterEvent("ADDON_LOADED")
events:RegisterEvent("PLAYER_ENTERING_WORLD")
events:RegisterEvent("PARTY_LEADER_CHANGED")

-- __________ FUNCTIONS __________ --
-- Returns mob NPCID from GUID.
MLA_mobIDfromGUID = setmetatable ({}, { __index = function(t, guid)
	local mobID = tonumber(strsub(guid, 6, 10), 16)
	t[guid] = mobID
	return mobID
end })

-- Handler
events:SetScript("OnEvent", function(self, event, ...)
	return self[event] and self[event](self, event, ...)
end)

-- ADDON_LOADED
function events:ADDON_LOADED(event, addon)
	if addon == "MasterLooterAssistant" then
		-- Enable all bosses on default.
		if not MLA_bossNPCID then
			MLA_bossNPCID = {
			[55294] = true, -- Ultraxion
			[52530] = true, -- Alysrazor
			[52409] = true, -- Ragnaros
			[46753] = true, -- Al'akir
			[60410] = true, -- Elegon
			[36597] = true, -- The Lich King
			[10184] = true, -- Onyxia
			[28859] = true, -- Malygos
			[28860] = true, -- Sartharion
			[69712] = true, -- Ji-Kun
			[68476] = true, -- Horridon
			[56173] = true, -- Madness of Deathwing: Deathwing
			[33136] = true, [33288] = true, -- Yogg-Saron: Guardian of Yogg-Saron, Yogg-Saron
			[16151] = true, [16152] = true, -- Attumen the Huntsman: Midnight, Attumen the Huntsman
			[20064] = true, [20063] = true, [20062] = true, [20060] = true, [19622] = true -- Kael'thas Sunstrider: Thaladred the Darkener, Master Engineer Telonicus,  Grand Astromancer Capernian, Lord Sanguinar, Kael'thas Sunstrider
			}

			print("|cff71C671Master Looter Assistant: |r"..L["To get started, use \"/mla\" or \"/mlassistant\" to configure your settings."])
		end

		-- Set default threshold to epic.
		if not MLA_LootThreshold then
			MLA_LootThreshold = 4
		end
	end
end

-- PLAYER_ENTERING_WORLD
function events:PLAYER_ENTERING_WORLD(event)
	local ininstance, instancetype = IsInInstance("player")
	local isgroupleader = UnitIsGroupLeader("player")
	local _, _, difficulty = GetInstanceInfo()
	local incombat = InCombatLockdown()
	local enable = {
		[1] = true, -- normal
		[2] = true, -- heroic
		[3] = true, -- 10 player
		[4] = true, -- 25 player
		[5] = true, -- heroic 10 player
		[6] = true -- heroic 25 player
	}

	if ininstance == 1 and instancetype == "raid" then
		if not enable[difficulty] then
			-- Return if instance type isn't an appropriate raid (eg. LFR/scenarios).
			return
		end

		if isgroupleader then
			print("|cff71C671Master Looter Assistant "..L["enabled!"])
			self:RegisterEvent("PLAYER_REGEN_DISABLED")
			self:RegisterEvent("PLAYER_REGEN_ENABLED")

			-- Print warning upon entering instance if someone else is set as loot master.
			if MLA_LootMaster then
				print("|cff71C671Master Looter Assistant: |r"..string.format(L["You currently have designated to pass loot master to another player. If %s is in the raid group, he/she will be set as the loot master. Use \"/mla looter\" while targeting a player to change the loot master or \"/mla clear\" to default back to yourself. You may also use the buttons in the interface options panel."], MLA_LootMaster))
			end

			-- Set ignore table.
			M.ignore = {
				[20060] = true, -- Kael'thas
				[20062] = true, -- Kael'thas
				[20063] = true, -- Kael'thas
				[20064] = true, -- Kael'thas
				[33136] = true -- Yogg-Saron
			}

			-- Enable CLEU and CMMY if logging in during a fight or passed lead mid fight.
			if incombat then
				self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
				self:RegisterEvent("CHAT_MSG_MONSTER_YELL")
			end
		else
			self:UnregisterEvent("PLAYER_REGEN_DISABLED")
			self:UnregisterEvent("PLAYER_REGEN_ENABLED")
			self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
			self:UnregisterEvent("CHAT_MSG_MONSTER_YELL")
		end
	end
end

-- PARTY_LEADER_CHANGED
events.PARTY_LEADER_CHANGED = events.PLAYER_ENTERING_WORLD

-- PLAYER_REGEN_DISABLED
function events:PLAYER_REGEN_DISABLED(event)
	-- Enable CLEU (and CMMY for Ragnaros) only when entering combat.
	self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	self:RegisterEvent("CHAT_MSG_MONSTER_YELL")
end

function events:PLAYER_REGEN_ENABLED(event)
	-- If leaving combat from mob that's not a boss then unregister CLEU and CMMY.
	if not M.nokill then
		self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
		self:UnregisterEvent("CHAT_MSG_MONSTER_YELL")
	end
end

-- COMBAT_LOG_EVENT_UNFILTERED
function events:COMBAT_LOG_EVENT_UNFILTERED(event, _, eventType, _, sourceGUID, sourceName, _, _, destGUID, destName, _, _, spellID)
	local mobIDa, mobIDb = MLA_mobIDfromGUID[sourceGUID], MLA_mobIDfromGUID[destGUID] -- NPCID
	local bossIDa, bossIDb = MLA_bossNPCID[mobIDa], MLA_bossNPCID[mobIDb] -- Boss is found in table.
	local incombat = InCombatLockdown()

	if spellID == 110063 then
		-- Madness of Deathwing kill trigger...
		M.nokill, M.mobName = nil
		M.loottrigger = true

		-- Register LO and CML for reset.
		self:RegisterEvent("LOOT_OPENED")
		if MLA_LootMaster ~= nil then
			self:RegisterEvent("CHAT_MSG_LOOT")
		end

		-- Unregister CLEU and CMMY.
		self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
		self:UnregisterEvent("CHAT_MSG_MONSTER_YELL")
		return
	elseif not bossIDa and not bossIDb then
		-- Return if mob is not a boss or is not enabled.
		return
	elseif eventType == "UNIT_DIED" and bossIDb and not M.ignore[mobIDb] then
		-- Trigger for reset when boss dies.
		M.nokill, M.mobName = nil
		M.loottrigger = true

		-- Register LO and CML for reset.
		self:RegisterEvent("LOOT_OPENED")
		if MLA_LootMaster ~= nil then
			self:RegisterEvent("CHAT_MSG_LOOT")
		end

		-- Unregister CLEU and CMMY.
		self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
		self:UnregisterEvent("CHAT_MSG_MONSTER_YELL")
		return
	elseif (mobIDa == 55294 and not incombat) or (spellID == 136767) then
		 -- Ignore Ultraxion's Twilight Shift and Horridon's Triple Puncture.
		return
	elseif M.nokill then
		-- Return if the boss is already registered.
		return
	end

	-- print(event, _, eventType, _, sourceGUID, sourceName, _, _, destGUID, destName, _, _, spellID)

	-- Watch PLMC to set threshold.
	self:RegisterEvent("PARTY_LOOT_METHOD_CHANGED")

	-- Set pull trigger and store the boss name.
	M.nokill = true
	M.mobName = bossIDa and sourceName or destName

	-- Only get the loot method and threshold if it's not already set.
	if not M.method and not M.threshold then
	M.method, M.threshold = GetLootMethod(), GetLootThreshold()
	else
		return
	end

	-- Define the loot master.
	local lootmaster = "player"

	if MLA_LootMaster then
		-- If a loot master is set, check if that player is in raid and set them to loot master instead.
		local name, server = MLA_LootMaster:match("^(%S*)%s*(.-)$")
		local num = GetNumGroupMembers()

		for i = 1, num do
			if UnitInRaid("player") then
				local raider = GetUnitName("raid"..i, true)
				if raider == MLA_LootMaster then
					lootmaster = name
					break
				end
			else
				local raider = GetUnitName("party"..i, true)
				if raider == MLA_LootMaster then
					lootmaster = name
					break
				end
			end
		end
	end

	if M.method ~= "master" then
		-- Set to master looter if it's not already.
		if M.threshold ~= MLA_LootThreshold then
			-- Threshold needs changed as well.
			SetLootMethod("master", lootmaster)
			M.thresholdtrigger = true
		else
			-- Threshold is already correct, only set loot master.
			SetLootMethod("master", lootmaster)
		end
	elseif M.threshold ~= MLA_LootThreshold then
		-- Already set to master looter but threshold is not set.
		if not MLA_LootThreshold then
			-- Backup in case for whatever reason it didn't get set as 4 by default.
			SetLootThreshold(4)
		else
			SetLootThreshold(MLA_LootThreshold)
		end
	end
end

-- CHAT_MSG_MONSTER_YELL
function events:CHAT_MSG_MONSTER_YELL(event, msg, ...)
	-- Ragnaros (to revert settings on normal)
	if msg == L["Too soon! ... You have come too soon..."] then
		M.nokill, M.mobName = nil
		M.loottrigger = true

		-- Register LO and CML for reset.
		self:RegisterEvent("LOOT_OPENED")
		if MLA_LootMaster ~= nil then
			self:RegisterEvent("CHAT_MSG_LOOT")
		end

		-- Unregister CLEU and CMMY.
		self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
		self:UnregisterEvent("CHAT_MSG_MONSTER_YELL")
	end
end

-- PARTY_LOOT_METHOD_CHANGED
function events:PARTY_LOOT_METHOD_CHANGED(event, ...)
	if M.thresholdtrigger then
		-- Set threshold on the initial pull.
		M.thresholdtrigger = nil

		if not MLA_LootThreshold then
			-- Backup in case for whatever reason it didn't get set as 4 by default.
			SetLootThreshold(4)
		else
			SetLootThreshold(MLA_LootThreshold)
		end
	elseif M.revertthreshold then
		-- Reset threshold on the kill.
		M.revertthreshold = nil

		SetLootThreshold(M.threshold)
		M.threshold = nil

		-- Unregister events.
		self:UnregisterEvent(event)
	else
		-- Loot method was changed after the pull but before the boss was killed.
		-- Find out what the current loot method and threshold are.
		local newmethod, newthreshold = GetLootMethod(), GetLootThreshold()

		if newmethod ~= "master" then
			-- If the loot method was changed...
			if newmethod ~= M.method then
				-- If the new loot method doesn't match the stored method, reset the pull using their new settings.
				-- Restore their threshold.
				SetLootThreshold(M.threshold)

				-- Reset triggers and information.
				M.method, M.threshold, M.mobName, M.nokill = nil

				-- Unregister PLMC.
				self:UnregisterEvent(event)

				print("|cff71C671Master Looter Assistant: |r"..string.format(L["You've changed your loot method before killing %s. Your previous loot threshold has been restored and your new settings will be saved next time you engage %s."], M.mobName, M.mobName))
			else
				-- Loot method was changed back to their previous, so treat it like a temporary disable.
				-- Restore their threshold.
				SetLootThreshold(M.threshold)

				-- Reset information.
				M.method, M.threshold = nil

				-- Unregister PLMC.
				self:UnregisterEvent(event)

				print("|cff71C671Master Looter Assistant: |r"..string.format(L["You've changed your loot method to your previous settings before killing %s. Your old threshold has been restored and functionality is temporarily disabled on this boss. To reenable functionality use \"/mla reset\"."], M.mobName))
			end
		end
	end
end

-- LOOT_OPENED
function events:LOOT_OPENED(event, ...)
	if not M.method or not M.threshold then
		-- If player temporarily disabled on a boss, reset the pull after the kill.
		M.loottrigger = nil

		-- Unregister LO.
		self:UnregisterEvent(event)
	elseif M.loottrigger then
		-- Reset pull and settings after the boss is killed.
		M.loottrigger = nil

		SetLootMethod(M.method)

		M.method = nil

		-- Trigger threshold reset.
		M.revertthreshold = true

		-- Unregister LO.
		self:UnregisterEvent(event)
	end
end

-- CHAT_MSG_LOOT
-- Used to revert settings if loot master is not the player and the player doesn't loot the boss/chest.
events.CHAT_MSG_LOOT = events.LOOT_OPENED

-- __________ SLASH COMMAND __________ --
SLASH_MASTERLOOTERASSISTANT1, SLASH_MASTERLOOTERASSISTANT2 = "/mla", "/mlassistant"

function SlashCmdList.MASTERLOOTERASSISTANT(msg, editbox)
	if msg == "looter" then
		-- Set target as stored loot master.
		MLA_SetLootMaster()
	elseif msg == "clear" then
		-- Clear stored loot master.
		MLA_ClearLootMaster()
	elseif msg == "reset" then
		-- Reset a boss pull (no settings revert).
		M.method, M.threshold, M.mobName, M.nokill = nil

		print("|cff71C671Master Looter Assistant: |r"..L["The current boss pull has been reset and your current settings will be stored on the next pull."])
	else
		-- This doesn't open directly to options the first time you load, so done twice to go immediately there.
		InterfaceOptionsFrame_OpenToCategory(M.Options)
		InterfaceOptionsFrame_OpenToCategory(M.Options)
	end
end