You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

558 lines
17 KiB

local _, addon = ...
local GetRaidRosterInfo = GetRaidRosterInfo;
local GetNumGroupMembers = GetNumGroupMembers;
local NotifyInspect = NotifyInspect;
local UnitGUID = UnitGUID;
local UnitExists = UnitExists;
local ClearInspectPlayer = ClearInspectPlayer;
local UnitIsPlayer = UnitIsPlayer;
local CanInspect = CanInspect;
local GetInventoryItemTexture = GetInventoryItemTexture;
local GetInventoryItemLink = GetInventoryItemLink;
local GetDetailedItemLevelInfo = GetDetailedItemLevelInfo;
local GetItemInfoInstant = GetItemInfoInstant;
local CreateFrame = CreateFrame;
local gsub = string.gsub;
local IsItemProgenitorSet = NarciAPI.IsItemProgenitorSet;
local GetInspectEncounterCount = addon.GetInspectEncounterCount;
local MainFrame, MouseOverFrame, Tooltip;
local TAB_HEIGHT = 32;
local ITEM_SIZE = 24;
local ITEM_PADDING = 4;
local PIXEL = NarciAPI.GetScreenPixelSize();
local GUID_CACHE = {};
local EQUIPMENT_ORDER = {
1, 2, 3, 15, 5, 9, 10, 6, 7, 8, 11, 12, 13, 14, 16, 17
};
local function ShortenPlayerGUID(guid)
if guid then
guid = string.match(guid, "Player%-%d+%-(.+)");
return guid --tonumber(guid, 16);
end
end
local function RemoveServerName(playerName)
return playerName and gsub(playerName, "-.+", "");
end
local function Delay_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
if self.t > 0 then
self:SetScript("OnUpdate", nil);
if self.delayCallback then
self:delayCallback();
end
end
end
local function Shared_OnDragStart()
MainFrame:StartMoving();
Tooltip:Hide();
end
local function Shared_OnDragStop()
MainFrame:StopMovingOrSizing();
end
local function SetUpFrameForDrag(f)
f:RegisterForDrag("LeftButton");
f:SetScript("OnDragStart", Shared_OnDragStart);
f:SetScript("OnDragStop", Shared_OnDragStop);
end
local ItemOutlinePool = {};
function ItemOutlinePool:Acquire()
if not self.frames then
self.frames = {};
self.liveFrames = {};
self.deadFrames = {};
self.total = 0;
self.numLive = 0;
self.numDead = 0;
end
local f;
if self.numDead > 0 then
f = self.deadFrames[self.numDead];
self.deadFrames[self.numDead] = nil;
self.numDead = self.numDead - 1;
else
self.total = self.total + 1;
self.frames[self.total] = CreateFrame("Frame", nil, MainFrame, "NarciRaidCheckItemOutlineTemplate");
f = self.frames[self.total];
end
self.numLive = self.numLive + 1;
f:ClearAllPoints();
f:Show();
return f
end
function ItemOutlinePool:KillFrame(frame)
frame:Hide();
frame:ClearAllPoints();
self.numLive = self.numLive - 1;
self.numDead = self.numDead + 1;
self.deadFrames[self.numDead] = frame;
end
function ItemOutlinePool:GetTotalFrames()
return self.total
end
local DataProvider = {};
function DataProvider:Wipe()
self.dataByGUID = {};
self.displayedOrder = {};
end
function DataProvider:CreatePlayerData(guid)
if not self.dataByGUID[guid] then
self.dataByGUID[guid] = {
["items"] = {},
};
end
end
function DataProvider:SetPlayerItemData(guid, slotID, itemLink)
self:CreatePlayerData(guid);
if not (self.dataByGUID[guid]["items"][slotID] and self.dataByGUID[guid]["items"][slotID].itemLink) then
self.dataByGUID[guid]["items"][slotID] = {
itemLink = itemLink,
itemID = itemLink and GetItemInfoInstant(itemLink),
level = itemLink and GetDetailedItemLevelInfo(itemLink),
};
end
end
function DataProvider:GetPlayerItemData(guid, slotID)
if self.dataByGUID[guid] then
return self.dataByGUID[guid]["items"][slotID]
end
end
function DataProvider:GetPlayerItemLink(guid, slotID)
if self.dataByGUID[guid] then
return self.dataByGUID[guid]["items"][slotID] and self.dataByGUID[guid]["items"][slotID].itemLink
end
end
function DataProvider:GetPlayerItemID(guid, slotID)
if self.dataByGUID[guid] then
return self.dataByGUID[guid]["items"][slotID] and self.dataByGUID[guid]["items"][slotID].itemID
end
end
function DataProvider:CalculatePlayerAverageItemLevel(guid)
if self.dataByGUID[guid] then
if not self.dataByGUID[guid].averageLevel then
local sum = 0;
local numItems = 0;
local items = self.dataByGUID[guid]["items"];
for slot, data in pairs(items) do
sum = sum + (data.level or 0);
numItems = numItems + 1;
end
self.dataByGUID[guid].averageLevel = (numItems > 0 and math.floor(sum/numItems * 1000 + 0.5)/1000) or 0;
end
return self.dataByGUID[guid].averageLevel
end
end
NarciRaidCheckFrameMixin = {};
function NarciRaidCheckFrameMixin:OnLoad()
MainFrame = self;
MouseOverFrame = self.MouseOverFrame;
Tooltip = self.Tooltip;
--Tooltip:SetClampRectInsets(2, 2, 2, 2);
SetUpFrameForDrag(self);
SetUpFrameForDrag(self.MouseOverFrame);
DataProvider:Wipe();
end
function NarciRaidCheckFrameMixin:OnHide()
end
function NarciRaidCheckFrameMixin:OnMouseUp(button)
if button == "RightButton" then
self:Hide();
end
end
function NarciRaidCheckFrameMixin:AcquireFrame()
if not self.frames then
self.frames = {};
self.numActive = 0;
end
local i = self.numActive + 1;
self.numActive = i;
if not self.frames[i] then
self.frames[i] = CreateFrame("Frame", nil, self, "NarciRaidCheckMemberFrameTemplate");
self.frames[i]:SetPoint("TOPLEFT", self, "TOPLEFT", 0, TAB_HEIGHT * PIXEL * (1 - i));
self.frames[i]:SetFrameID(i);
end
self.frames[i]:Show();
return self.frames[i];
end
function NarciRaidCheckFrameMixin:GetFrameByIndex(i)
return self.frames[i];
end
function NarciRaidCheckFrameMixin:ReleaseFrames()
if self.frames then
for i = 1, #self.frames do
self.frames[i]:Hide();
end
end
self.numActive = 0;
end
function NarciRaidCheckFrameMixin:UpdateRoster()
self:ReleaseFrames();
local numPeople = GetNumGroupMembers();
local f;
local name, rank, subgroup, level, class, fileName, zone, online;
for i = 1, numPeople do
name, rank, subgroup, level, class, fileName, zone, online = GetRaidRosterInfo(i);
if name then
f = self:AcquireFrame();
f.PlayerName:SetText(RemoveServerName(name));
end
end
self:SetHeight(16 * math.max(self.numActive, 1));
self.memberIndex = 0;
self:CheckNextMember();
end
local function UnitIsValid(unit)
return UnitExists(unit) and CanInspect(unit)
end
function NarciRaidCheckFrameMixin:CheckNextMember()
local i, unit;
while self.memberIndex <= self.numActive do
i = self.memberIndex + 1;
self.memberIndex = i;
unit = "raid"..i;
if UnitIsValid(unit) then
break
end
end
if i <= self.numActive and UnitIsValid(unit) then
self.targetGUID = UnitGUID(unit);
self.targetUnit = unit;
self:RegisterEvent("INSPECT_READY");
NotifyInspect(unit);
else
self:StopChecking();
end
end
function NarciRaidCheckFrameMixin:StopChecking()
self:UnregisterEvent("INSPECT_READY");
end
function NarciRaidCheckFrameMixin:OnEvent(event, ...)
if event == "INSPECT_READY" then
self:OnInspectionReady(...);
end
if event =="INSPECT_ACHIEVEMENT_READY" then
self:OnAchievementReady(...);
end
if event == "PLAYER_TARGET_CHANGED" then
self:OnTargetChanged();
end
end
function NarciRaidCheckFrameMixin:OnInspectionReady(guid)
if guid == self.targetGUID then
self.t = -0.1;
self.delayCallback = self.ProcessInspectedPlayer;
self:SetScript("OnUpdate", Delay_OnUpdate);
end
end
function NarciRaidCheckFrameMixin:OnAchievementReady(guid)
if guid == self.targetGUID then
local f = self:GetFrameByIndex(self.memberIndex);
f.BossCount:SetText(GetInspectEncounterCount());
end
end
function NarciRaidCheckFrameMixin:ProcessInspectedPlayer()
self:UnregisterEvent("INSPECT_READY");
local unit = self.targetUnit;
local guid = self.targetGUID;
local f = self:GetFrameByIndex(self.memberIndex);
f.guid = guid;
local slotID, link;
local complete = true;
for i = 1, #EQUIPMENT_ORDER do
slotID = EQUIPMENT_ORDER[i];
link = GetInventoryItemLink(unit, slotID);
if link then
link = string.match(link, "(item:[%-?%d:]+)");
end
DataProvider:SetPlayerItemData(guid, slotID, link);
complete = (f:SetMemberItem(i, slotID, GetInventoryItemTexture(unit, slotID), link)) and complete;
if not complete then
break
end
end
if complete then
f:OnItemLoadingComplete();
ClearInspectPlayer();
self.delayCallback = nil;
else
self.t = -0.15;
self.delayCallback = self.ProcessInspectedPlayer;
end
self:SetScript("OnUpdate", Delay_OnUpdate);
end
function NarciRaidCheckFrameMixin:CheckTarget()
local unit = "target";
if UnitIsValid(unit) then
self:ReleaseFrames();
local f = self:AcquireFrame();
local _, classFilename = UnitClass(unit);
f.PlayerName:SetText( RemoveServerName( UnitName(unit) ));
f.PlayerName:SetTextColor( GetClassColor(classFilename) )
self.memberIndex = 1;
self.targetGUID = UnitGUID(unit);
self.targetUnit = unit;
self:RegisterEvent("INSPECT_READY");
NotifyInspect(unit);
end
end
function NarciRaidCheckFrameMixin:InspectUnitAchievements(unit)
ClearAchievementComparisonUnit();
self:RegisterEvent("INSPECT_ACHIEVEMENT_READY");
SetAchievementComparisonUnit(unit);
end
function NarciRaidCheckFrameMixin:CheckNewTarget()
local unit = "target";
if UnitIsValid(unit) then
if not self.memberIndex then
self.memberIndex = 0;
end
local f = self:AcquireFrame();
local _, classFilename = UnitClass(unit);
local guid = UnitGUID(unit);
f.guid = guid;
f.PlayerName:SetText( RemoveServerName( UnitName(unit) ));
f.PlayerName:SetTextColor( GetClassColor(classFilename) );
self.memberIndex = self.memberIndex + 1;
self.targetGUID = guid;
self.targetUnit = unit;
self:RegisterEvent("INSPECT_READY");
NotifyInspect(unit);
self:InspectUnitAchievements(unit);
end
end
function NarciRaidCheckFrameMixin:OnTargetChanged()
local unit = "target";
if UnitIsValid(unit) then
local guid = UnitGUID(unit);
guid = ShortenPlayerGUID(guid);
if not GUID_CACHE[guid] then
GUID_CACHE[guid] = true;
self:CheckNewTarget();
end
end
end
function NarciRaidCheckFrameMixin:SetManualCheck(state)
if state then
self:Show();
self:RegisterEvent("PLAYER_TARGET_CHANGED");
else
self:UnregisterEvent("PLAYER_TARGET_CHANGED");
end
end
local function Tooltip_ShowItem(anchor, itemLink)
Tooltip:Hide();
if itemLink then
Tooltip:SetOwner(anchor, "ANCHOR_NONE");
Tooltip:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -2);
Tooltip:SetHyperlink(itemLink);
Tooltip:SetFrameStrata("DIALOG");
Tooltip:Show();
end
end
function Tooltip_ShowUnit(unit)
if unit and UnitExists(unit) then
Tooltip:SetHyperlink(string.format("unit:%s", UnitGUID(unit)));
Tooltip:Show();
else
Tooltip:Hide();
end
end
local function MemberFrame_OnEnter(self)
MouseOverFrame:ClearAllPoints();
MouseOverFrame:SetParent(self);
MouseOverFrame:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0);
MouseOverFrame:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0);
MouseOverFrame:Show();
end
local function MemberFrame_OnLeave(self)
if not self:IsMouseOver() then
MouseOverFrame:Hide();
end
end
local function MemberFrame_OnMouseUp(self)
MainFrame:Hide();
end
local function ItemButton_OnEnter(self)
self.Icon:SetVertexColor(1, 1, 1);
Tooltip_ShowItem(self, DataProvider:GetPlayerItemLink(self:GetParent().guid, self.slotID));
MemberFrame_OnEnter(self:GetParent());
end
local function ItemButton_Leave(self)
if self.isLoaded then
self.Icon:SetVertexColor(0.67, 0.67, 0.67);
else
self.Icon:SetVertexColor(0.67, 0.25, 0.25);
end
Tooltip:Hide();
MemberFrame_OnLeave(self:GetParent());
end
NarciRaidCheckMemberFrameMixin = {};
function NarciRaidCheckMemberFrameMixin:OnLoad()
self:SetHeight(TAB_HEIGHT * PIXEL);
self.SpecIcon:SetSize(ITEM_SIZE * PIXEL, ITEM_SIZE * PIXEL);
self.SpecIcon:SetPoint("LEFT", self, "LEFT", ITEM_PADDING * PIXEL, 0);
self.PlayerName:SetPoint("LEFT", self, "LEFT", (ITEM_SIZE + 2 * ITEM_PADDING) * PIXEL, 0);
local width = (ITEM_SIZE + 2 * ITEM_PADDING) * PIXEL + 120;
self.leftWidth = width;
self:SetWidth(width + (ITEM_SIZE + ITEM_PADDING) * PIXEL * 16);
self:SetScript("OnEnter", MemberFrame_OnEnter);
self:SetScript("OnLeave", MemberFrame_OnLeave);
self:SetScript("OnMouseUp", MemberFrame_OnMouseUp);
SetUpFrameForDrag(self);
end
function NarciRaidCheckMemberFrameMixin:SetFrameID(id)
self.id = id;
if id % 2 == 1 then
self.Background:SetColorTexture(0.1, 0.1, 0.1);
else
self.Background:SetColorTexture(0.13, 0.13, 0.13);
end
end
function NarciRaidCheckMemberFrameMixin:SetMemberItem(id, slotID, texture, itemLink)
if not self.itemButtons then
self.itemButtons = {};
end
if not self.itemButtons[id] then
self.itemButtons[id] = CreateFrame("Button", nil, self);
local f = self.itemButtons[id];
local a = ITEM_SIZE*PIXEL;
f.id = id;
f.slotID = slotID;
SetUpFrameForDrag(f);
f:SetScript("OnEnter", ItemButton_OnEnter);
f:SetScript("OnLeave", ItemButton_Leave);
f:SetSize(a, a);
f:SetPoint("LEFT", self, "LEFT", self.leftWidth + ( (ITEM_SIZE + ITEM_PADDING) * PIXEL * (id - 1)), 0);
f.Icon = f:CreateTexture(nil, "OVERLAY");
f.Icon:SetSize(a, a);
f.Icon:SetPoint("CENTER", f, "CENTER", 0, 0);
f.Icon:SetTexCoord(0.075, 0.925, 0.075, 0.925);
end
self.itemButtons[id].Icon:SetTexture(texture);
--self.itemButtons[id].itemLink = itemLink;
local isLoaded = itemLink ~= nil;
if isLoaded then
self.itemButtons[id].Icon:SetVertexColor(0.67, 0.67, 0.67);
else
self.itemButtons[id].Icon:SetVertexColor(0.67, 0.25, 0.25);
end
self.itemButtons[id].isLoaded = isLoaded;
return (not texture) or (texture and isLoaded)
end
function NarciRaidCheckMemberFrameMixin:OnItemLoadingComplete()
--Release item outlines
if self.outlines then
for i = 1, #self.outlines do
ItemOutlinePool:KillFrame(self.outlines[i]);
end
end
self.outlines = {};
local itemID;
local numOwned = 0;
local guid = self.guid;
local outline, slotID;
for i = 1, #EQUIPMENT_ORDER do
if self.itemButtons[i] and self.itemButtons[i].isLoaded then
slotID = EQUIPMENT_ORDER[i];
itemID = DataProvider:GetPlayerItemID(guid, slotID);
if IsItemProgenitorSet(itemID) then
numOwned = numOwned + 1;
outline = ItemOutlinePool:Acquire();
outline:SetParent(self.itemButtons[i]);
outline:SetPoint("CENTER", self.itemButtons[i], "CENTER", 0, 0);
outline.Exclusion:SetSize(ITEM_SIZE*PIXEL, ITEM_SIZE*PIXEL);
outline.Selection:SetSize((ITEM_SIZE + 2)*PIXEL, (ITEM_SIZE + 2)*PIXEL);
self.outlines[numOwned] = outline;
end
end
end
self.ItemCount:SetText(math.floor( DataProvider:CalculatePlayerAverageItemLevel(guid) + 0.25 )); --average item level
local unit = MainFrame.targetUnit;
local specID = GetInspectSpecialization(unit);
local _, specName, specIcon;
if specID then
_, specName, _, specIcon = GetSpecializationInfoByID(specID, UnitSex(unit));
end
self.SpecIcon:SetTexture(specIcon);
end
--[[
/run NarciRaidCheckFrame:UpdateRoster()
/run NarciRaidCheckFrame:CheckTarget()
/run NarciRaidCheckFrame:SetManualCheck(true)
/run NarciRaidCheckTooltip:SetHyperlink(format("unit:%s", UnitGUID("target")));
name, rank, subgroup, level, class, fileName,
zone, online, isDead, role, isML, combatRole = GetRaidRosterInfo(raidIndex);
GROUP_ROSTER_UPDATE
--]]