786 lines
27 KiB
Lua
786 lines
27 KiB
Lua
--[[
|
|
This file is part of Decursive.
|
|
|
|
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
|
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
|
|
|
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
|
is no longer free software, all rights are reserved to its author (John Wellesz).
|
|
|
|
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
|
To distribute Decursive through other means a special authorization is required.
|
|
|
|
|
|
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
|
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
|
|
|
Decursive is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
--]]
|
|
-------------------------------------------------------------------------------
|
|
|
|
local addonName, T = ...;
|
|
-- big ugly scary fatal error message display function {{{
|
|
if not T._FatalError then
|
|
-- the beautiful error popup : {{{ -
|
|
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
|
text = "|cFFFF0000Decursive Error:|r\n%s",
|
|
button1 = "OK",
|
|
OnAccept = function()
|
|
return false;
|
|
end,
|
|
timeout = 0,
|
|
whileDead = 1,
|
|
hideOnEscape = 1,
|
|
showAlert = 1,
|
|
}; -- }}}
|
|
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
|
end
|
|
-- }}}
|
|
if not T._LoadedFiles or not T._LoadedFiles["Dcr_Events.lua"] then
|
|
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_Events.lua not loaded)"); end;
|
|
DecursiveInstallCorrupted = true;
|
|
return;
|
|
end
|
|
|
|
local D = Dcr;
|
|
--D:SetDateAndRevision("$Date: 2008-09-16 00:25:13 +0200 (mar., 16 sept. 2008) $", "$Revision: 81755 $");
|
|
|
|
|
|
local L = D.L;
|
|
local LC = D.LC;
|
|
local DC = DcrC;
|
|
local DS = DC.DS;
|
|
|
|
local RaidRosterCache = { };
|
|
local SortingTable = { };
|
|
D.Status.Unit_Array_GUIDToUnit = { };
|
|
D.Status.Unit_Array_UnitToGUID = { };
|
|
|
|
D.Status.InternalPrioList = { };
|
|
D.Status.InternalSkipList = { };
|
|
D.Status.Unit_Array = { };
|
|
|
|
local pairs = _G.pairs;
|
|
local ipairs = _G.ipairs;
|
|
local type = _G.type;
|
|
local select = _G.select;
|
|
local UnitIsFriend = _G.UnitIsFriend;
|
|
local UnitCanAttack = _G.UnitCanAttack;
|
|
local GetNumRaidMembers = _G.GetNumRaidMembers;
|
|
local GetNumPartyMembers = _G.GetNumPartyMembers;
|
|
local GetRaidRosterInfo = _G.GetRaidRosterInfo;
|
|
local random = _G.random;
|
|
local UnitIsUnit = _G.UnitIsUnit;
|
|
local UnitClass = _G.UnitClass;
|
|
local UnitExists = _G.UnitExists;
|
|
local UnitGUID = _G.UnitGUID;
|
|
local table = _G.table;
|
|
local t_insert = _G.table.insert;
|
|
local str_upper = _G.string.upper;
|
|
local MAX_RAID_MEMBERS = _G.MAX_RAID_MEMBERS;
|
|
local setmetatable = _G.setmetatable;
|
|
local rawget = _G.rawget;
|
|
local GetTime = _G.GetTime;
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- GROUP STATUS UPDATE, these functions update the UNIT table to scan {{{
|
|
-------------------------------------------------------------------------------
|
|
|
|
--[=[
|
|
local function AddToSort (unit, GUID, index) -- // {{{
|
|
if (D.profile.Random_Order and
|
|
(not D.Status.InternalPrioList[GUID]) and not GUID~=MyGUID) then
|
|
index = random (1, 3000);
|
|
end
|
|
SortingTable[unit] = index;
|
|
--D:Debug("Adding to sort: ", unit, index);
|
|
end --}}}
|
|
--]=]
|
|
|
|
|
|
-- Raid/Party Name Check Function (a terrible function, need optimising)
|
|
-- this returns the UnitID that the Name points to
|
|
-- this does not check "target" or "mouseover"
|
|
--[=[
|
|
function D:NameToUnit( Name ) --{{{
|
|
|
|
local numRaidMembers = GetNumRaidMembers();
|
|
local FoundUnit = false;
|
|
|
|
|
|
if (not Name) then
|
|
return false;
|
|
end
|
|
|
|
if self.Status.Unit_Array_NameToUnit[Name] ~= nil then
|
|
return self.Status.Unit_Array_NameToUnit[Name];
|
|
end
|
|
|
|
if (numRaidMembers == 0) then
|
|
if (Name == (self:UnitName("player"))) then
|
|
FoundUnit = "player";
|
|
elseif (Name == (self:UnitName("pet"))) then
|
|
FoundUnit = "pet";
|
|
elseif GetNumPartyMembers() > 0 then
|
|
if (Name == (self:UnitName("party1"))) then
|
|
FoundUnit = "party1";
|
|
elseif (Name == (self:UnitName("party2"))) then
|
|
FoundUnit = "party2";
|
|
elseif (Name == (self:UnitName("party3"))) then
|
|
FoundUnit = "party3";
|
|
elseif (Name == (self:UnitName("party4"))) then
|
|
FoundUnit = "party4";
|
|
elseif (Name == (self:UnitName("partypet1"))) then
|
|
FoundUnit = "partypet1";
|
|
elseif (Name == (self:UnitName("partypet2"))) then
|
|
FoundUnit = "partypet2";
|
|
elseif (Name == (self:UnitName("partypet3"))) then
|
|
FoundUnit = "partypet3";
|
|
elseif (Name == (self:UnitName("partypet4"))) then
|
|
FoundUnit = "partypet4";
|
|
end
|
|
end
|
|
else
|
|
-- we are in a raid
|
|
local i;
|
|
local foundmembers = 0;
|
|
local RaidName;
|
|
for i=1, MAX_RAID_MEMBERS do
|
|
RaidName = (GetRaidRosterInfo(i));
|
|
|
|
if RaidName then
|
|
|
|
foundmembers = foundmembers + 1;
|
|
|
|
if ( Name == RaidName) then
|
|
FoundUnit = "raid"..i;
|
|
break;
|
|
end
|
|
if ( self.profile.Scan_Pets and Name == (self:UnitName("raidpet"..i))) then
|
|
FoundUnit = "raidpet"..i;
|
|
break;
|
|
end
|
|
|
|
if foundmembers == numRaidMembers then
|
|
break;
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
self.Status.Unit_Array_NameToUnit[Name] = FoundUnit;
|
|
|
|
return FoundUnit;
|
|
|
|
end --}}}
|
|
--]=]
|
|
-- }}}
|
|
|
|
|
|
|
|
DC.ClassNumToLName = {
|
|
[11] = LC[DC.CLASS_DRUID],
|
|
[12] = LC[DC.CLASS_HUNTER],
|
|
[13] = LC[DC.CLASS_MAGE],
|
|
[14] = LC[DC.CLASS_PALADIN],
|
|
[15] = LC[DC.CLASS_PRIEST],
|
|
[16] = LC[DC.CLASS_ROGUE],
|
|
[17] = LC[DC.CLASS_SHAMAN],
|
|
[18] = LC[DC.CLASS_WARLOCK],
|
|
[19] = LC[DC.CLASS_WARRIOR],
|
|
[20] = LC[DC.CLASS_DEATHKNIGHT],
|
|
[21] = LC[DC.CLASS_HERO],
|
|
}
|
|
|
|
DC.ClassLNameToNum = D:tReverse(DC.ClassNumToLName);
|
|
|
|
DC.ClassNumToUName = {
|
|
[11] = DC.CLASS_DRUID,
|
|
[12] = DC.CLASS_HUNTER,
|
|
[13] = DC.CLASS_MAGE,
|
|
[14] = DC.CLASS_PALADIN,
|
|
[15] = DC.CLASS_PRIEST,
|
|
[16] = DC.CLASS_ROGUE,
|
|
[17] = DC.CLASS_SHAMAN,
|
|
[18] = DC.CLASS_WARLOCK,
|
|
[19] = DC.CLASS_WARRIOR,
|
|
[20] = DC.CLASS_DEATHKNIGHT,
|
|
[21] = DC.CLASS_HERO,
|
|
}
|
|
|
|
DC.ClassUNameToNum = D:tReverse(DC.ClassNumToUName);
|
|
|
|
|
|
-- this gets an array of units for us to check
|
|
|
|
do
|
|
|
|
local i = 1;
|
|
local D = D;
|
|
local _ = false; -- a local dummy trash variable
|
|
|
|
local MAX_RAID_MEMBERS = _G.MAX_RAID_MEMBERS;
|
|
|
|
local UnitToGUID = {};
|
|
local GUIDToUnit = {};
|
|
|
|
local raidnum = 0;
|
|
|
|
local UnitToGUID_mt = { __index = function(self, unit)
|
|
local GUID = UnitGUID(unit) or false;
|
|
|
|
self[unit] = GUID;
|
|
GUIDToUnit[GUID] = unit;
|
|
|
|
--[=[
|
|
if (D.db.global.debugging) then
|
|
if not GUID then
|
|
D:errln("UnitToGUID_mt: no GUID for: ", unit); -- this is not an error, it's to see when raid# ids are not contiguous...
|
|
end
|
|
end
|
|
--]=]
|
|
|
|
|
|
return self[unit];
|
|
end };
|
|
|
|
|
|
local GUIDToUnit_ScannedAll = false;
|
|
local lookforpets = true;
|
|
local GUIDToUnit_mt = { __index = function(self, GUID)
|
|
-- {{{
|
|
|
|
if GUIDToUnit_ScannedAll then
|
|
self[GUID] = false;
|
|
D:Debug("GUIDToUnit_mt: %s is not in our group!", GUID);
|
|
return self[GUID];
|
|
end
|
|
|
|
if (not GUID) then
|
|
D:errln("GUIDToUnit_mt: no GUID! ");
|
|
return false;
|
|
end
|
|
|
|
local unit = false;
|
|
|
|
|
|
if GUID == DC.MyGUID then
|
|
unit = "player";
|
|
elseif GUID == UnitToGUID["pet"] then
|
|
unit = "pet";
|
|
elseif (raidnum == 0) then
|
|
if GetNumPartyMembers() > 0 then
|
|
if GUID == UnitToGUID["party1"] then
|
|
unit = "party1";
|
|
elseif GUID == UnitToGUID["party2"] then
|
|
unit = "party2";
|
|
elseif GUID == UnitToGUID["party3"] then
|
|
unit = "party3";
|
|
elseif GUID == UnitToGUID["party4"] then
|
|
unit = "party4";
|
|
elseif D.profile.Scan_Pets then
|
|
if GUID == UnitToGUID["partypet1"] then
|
|
unit = "partypet1";
|
|
elseif GUID == UnitToGUID["partypet2"] then
|
|
unit = "partypet2";
|
|
elseif GUID == UnitToGUID["partypet3"] then
|
|
unit = "partypet3";
|
|
elseif GUID == UnitToGUID["partypet4"] then
|
|
unit = "partypet4";
|
|
end
|
|
end
|
|
end
|
|
else
|
|
-- we are in a raid
|
|
local i;
|
|
local foundmembers = 0;
|
|
local RaidGUID;
|
|
for i=1, MAX_RAID_MEMBERS do
|
|
RaidGUID = UnitToGUID[ "raid"..i];
|
|
|
|
if RaidGUID then
|
|
|
|
foundmembers = foundmembers + 1;
|
|
|
|
if GUID == RaidGUID then
|
|
unit = "raid"..i;
|
|
break;
|
|
end
|
|
|
|
if lookforpets and D.profile.Scan_Pets and GUID == UnitToGUID["raidpet"..i] then
|
|
unit = "raidpet"..i;
|
|
break;
|
|
end
|
|
|
|
if foundmembers == raidnum then
|
|
break;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if not unit then
|
|
GUIDToUnit_ScannedAll = true;
|
|
end
|
|
|
|
self[GUID] = unit;
|
|
|
|
return self[GUID];
|
|
end };
|
|
--}}}
|
|
|
|
|
|
local function IsInSkipList ( GUID, group, classNum ) -- {{{
|
|
if (D.Status.InternalSkipList[GUID] or D.Status.InternalSkipList[group] or D.Status.InternalSkipList[classNum]) then
|
|
return true;
|
|
end
|
|
|
|
return false;
|
|
end -- }}}
|
|
|
|
local function IsInSkipOrPriorList( GUID, group, classNum ) --{{{
|
|
|
|
if (IsInSkipList ( GUID, group, classNum )) then
|
|
return true;
|
|
end
|
|
|
|
if (D.Status.InternalPrioList[GUID] or D.Status.InternalPrioList[group] or D.Status.InternalPrioList[classNum]) then
|
|
return true;
|
|
end
|
|
|
|
return false;
|
|
end --}}}
|
|
|
|
|
|
local ClassPrio = { };
|
|
local GroupsPrio = { };
|
|
|
|
local currentGroup = 0; -- the group we are in
|
|
|
|
local function GetUnitDefaultPriority (RaidId, UnitGroup) -- {{{
|
|
|
|
if (not UnitGroup) then
|
|
return RaidId;
|
|
end
|
|
|
|
if (UnitGroup >= currentGroup) then
|
|
return ( 8 - ( UnitGroup - currentGroup ) ) * 100 + (41 - RaidId);
|
|
end
|
|
|
|
if (UnitGroup < currentGroup) then
|
|
return (currentGroup - UnitGroup) * 100 + (41 - RaidId);
|
|
end
|
|
end -- }}}
|
|
|
|
local function GetUnitPriority(Unit, RaidId, UnitGroup, UNClass, IsPet) -- {{{
|
|
|
|
-- A little explanation of the principle behind this function {{{
|
|
--[=[ ****************************************************************************
|
|
levels of priority:
|
|
|
|
0 --> PriorityList
|
|
1 --> Group
|
|
2 --> Class
|
|
3 --> Default (Decursive "natural" order: our group, groups after, groups before)
|
|
4 --> Pets
|
|
|
|
- 8 groups with 5 persons maximum per group
|
|
- 10 classes with 80 persons max for each class (Pets may be counted)
|
|
- 80 persons for default (including possible pets)
|
|
|
|
Priority list: 1,000,000 till 100,000,000
|
|
Group indexes: 10,000, 20,000, 30,000, till 80,000
|
|
class indexes: 1,000, 2,000, 3,000, till 10,000
|
|
default indexes: 100 to 800 (player's index will be 900)
|
|
pet indexes: Same as above but * -1
|
|
|
|
We make additions, exemple:
|
|
- Our current group is the group 7
|
|
- The resulting default groups priorities are:
|
|
7:800 8: 700, 1:600, 2: 500, 3: 400, 4: 300, 5: 200, 6:100
|
|
- Archarodim, Mage from Group 5 (23rd unit of the raid)
|
|
- Unit Archarodim priority is 223
|
|
- Class Mage priority is 4000
|
|
- Group 5 priority is 20000
|
|
|
|
--> Archarodim priority is 200 + 23 + 4000 + 20000 = 24223
|
|
**************************************************************************** }}} ]=]
|
|
|
|
-- Get Decursive's natural default priority of the unit
|
|
local UnitPriority = GetUnitDefaultPriority(RaidId, UnitGroup);
|
|
|
|
-- Get the class priority if available
|
|
if ( UNClass and ClassPrio[ DC.ClassUNameToNum [UNClass] ] ) then
|
|
UnitPriority = UnitPriority + ( 10 + 1 - ClassPrio[DC.ClassUNameToNum [UNClass]]) * 1000; -- XXX 10 (Deathknight) is no good
|
|
end
|
|
|
|
-- Get the group priority if available
|
|
if (UnitGroup and GroupsPrio[UnitGroup]) then
|
|
UnitPriority = UnitPriority + (8 + 1 - GroupsPrio[UnitGroup]) * 10000;
|
|
end
|
|
|
|
-- Get the priority list index if available
|
|
if not IsPet then
|
|
local Unit_GUID = UnitToGUID[Unit];
|
|
|
|
local PrioListIndex = 100;
|
|
|
|
-- get the higher of the three...
|
|
if (D.Status.InternalPrioList[Unit_GUID] and D.Status.InternalPrioList[Unit_GUID] < PrioListIndex) then
|
|
PrioListIndex = D.Status.InternalPrioList[Unit_GUID];
|
|
end
|
|
|
|
if (D.Status.InternalPrioList[UnitGroup] and D.Status.InternalPrioList[UnitGroup] < PrioListIndex) then
|
|
PrioListIndex = D.Status.InternalPrioList[UnitGroup];
|
|
end
|
|
|
|
if (D.Status.InternalPrioList[ DC.ClassUNameToNum [UNClass] ] and D.Status.InternalPrioList[ DC.ClassUNameToNum [UNClass] ] < PrioListIndex) then
|
|
PrioListIndex = D.Status.InternalPrioList[ DC.ClassUNameToNum [UNClass] ];
|
|
end
|
|
|
|
|
|
if ( PrioListIndex < 100) then
|
|
UnitPriority = UnitPriority + (100 + 1 - PrioListIndex) * 1000000;
|
|
end
|
|
end
|
|
|
|
if IsPet then
|
|
UnitPriority = UnitPriority * -1;
|
|
end
|
|
|
|
return UnitPriority;
|
|
end -- }}}
|
|
|
|
|
|
local RaidRosterCache = {};
|
|
|
|
local pet;
|
|
function D:GetUnitArray() --{{{
|
|
-- if the groups composition did not changed
|
|
if not self.Groups_datas_are_invalid or not self.DcrFullyInitialized then
|
|
return;
|
|
end
|
|
self.Groups_datas_are_invalid = false;
|
|
|
|
self:Debug ("|cFFFF44FF-->|r Updating Units Array");
|
|
|
|
local pGUID;
|
|
raidnum = GetNumRaidMembers();
|
|
|
|
if DC.MyGUID == "NONE" then
|
|
|
|
self:Debug("|cFFFF0000DC.MyGUID was nil!!|r");
|
|
|
|
DC.MyGUID = (UnitGUID("player"));
|
|
|
|
if not DC.MyGUID then
|
|
DC.MyGUID = "NONE";
|
|
self:Debug("|cFFFF0000DC.MyGUID is STILL nil!!|r");
|
|
end
|
|
|
|
end
|
|
|
|
local MyGUID = DC.MyGUID;
|
|
|
|
-- clear all the arrays
|
|
local Status = self.Status;
|
|
Status.InternalPrioList = {}; -- these lists contains only units currently present
|
|
Status.InternalSkipList = {};
|
|
SortingTable = {};
|
|
Status.Unit_Array_GUIDToUnit = {};
|
|
Status.Unit_Array_UnitToGUID = {};
|
|
|
|
UnitToGUID = setmetatable(UnitToGUID, UnitToGUID_mt); -- we could simply erase this one to prevent garbage
|
|
GUIDToUnit = setmetatable(GUIDToUnit, GUIDToUnit_mt); -- this one cannot be erased (memory leak due to GUID...)
|
|
GUIDToUnit_ScannedAll = false;
|
|
|
|
if Status.TestLayout then
|
|
D:GetFakeUnit_array ();
|
|
return;
|
|
end
|
|
|
|
|
|
local unit;
|
|
|
|
|
|
-- ############### PARSE PRIO AND SKIP LIST ###############
|
|
|
|
GroupsPrio, ClassPrio = D:MakeGroupsAndClassPrio();
|
|
|
|
lookforpets = false;
|
|
|
|
-- First clean and load the prioritylist (remove missing units)
|
|
for i, ListEntry in ipairs(self.profile.PriorityList) do
|
|
|
|
-- first add GUIDs present in our raid group
|
|
if (type(ListEntry) == "string") then
|
|
unit = GUIDToUnit[ListEntry];
|
|
if (unit) then
|
|
Status.InternalPrioList[ListEntry] = i;
|
|
end
|
|
|
|
else -- if ListEntry is not a string, then it's a number
|
|
-- representing the groups or the classes
|
|
|
|
Status.InternalPrioList[ListEntry] = i;
|
|
end
|
|
end
|
|
|
|
-- Get a cleaned skip list
|
|
for i, ListEntry in ipairs(self.profile.SkipList) do
|
|
if (type(ListEntry) == "string") then
|
|
unit = GUIDToUnit[ListEntry];
|
|
if (unit) then
|
|
Status.InternalSkipList[ListEntry] = i;
|
|
end
|
|
else
|
|
Status.InternalSkipList[ListEntry] = i;
|
|
end
|
|
end
|
|
lookforpets = true;
|
|
|
|
|
|
-- if we are not in a raid but in a party
|
|
if (raidnum == 0) then
|
|
currentGroup = 1; -- this is used to compute the default priorities
|
|
-- Add the player to the main list if needed
|
|
if not IsInSkipOrPriorList(MyGUID, false, DC.ClassUNameToNum[DC.MyClass]) then
|
|
-- the player is not in a priority state, add to default prio
|
|
SortingTable["player"] = 900;
|
|
Status.Unit_Array_GUIDToUnit[MyGUID] = "player";
|
|
|
|
|
|
elseif not IsInSkipList(MyGUID, false, DC.ClassUNameToNum[DC.MyClass]) then
|
|
-- The player is contained within a priority rule
|
|
SortingTable["player"] = GetUnitPriority ("player", 1, 1, DC.MyClass );
|
|
Status.Unit_Array_GUIDToUnit[MyGUID] = "player";
|
|
|
|
end
|
|
|
|
local unit = "";
|
|
|
|
-- add the party members and their pets... if they exist
|
|
for i = 1, 4 do
|
|
unit = "party"..i;
|
|
|
|
if (UnitExists(unit)) then
|
|
|
|
pGUID = UnitToGUID[unit];
|
|
|
|
if (not pGUID) then -- at logon sometimes pGUID is nil...
|
|
pGUID = unit;
|
|
end
|
|
|
|
-- check the GUID to see if we skip
|
|
if (not IsInSkipList(pGUID, nil, DC.ClassUNameToNum[(select(2, UnitClass(unit)))])) then
|
|
|
|
Status.Unit_Array_GUIDToUnit[pGUID] = unit;
|
|
|
|
SortingTable[unit] = GetUnitPriority (unit, i + 1, 1, (select(2, UnitClass(unit)) ) );
|
|
|
|
end
|
|
|
|
if ( self.profile.Scan_Pets ) then
|
|
|
|
pet = "partypet"..i;
|
|
|
|
if (UnitExists(pet)) then
|
|
pGUID = UnitToGUID[pet];
|
|
|
|
if (not pGUID) then -- at logon sometimes pGUID is nil...
|
|
pGUID = pet;
|
|
end
|
|
|
|
SortingTable[pet] = GetUnitPriority (pet, i + 1, 1, (select(2, UnitClass(pet))), true);
|
|
Status.Unit_Array_GUIDToUnit[pGUID] = pet;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- add our own pet
|
|
if ( self.profile.Scan_Pets ) then
|
|
if (UnitExists("pet")) then
|
|
SortingTable["pet"] = -900;
|
|
Status.Unit_Array_GUIDToUnit[UnitToGUID["pet"]] = "pet";
|
|
end
|
|
end
|
|
|
|
if ( raidnum > 0 ) then -- if we are in a raid
|
|
currentGroup = 0;
|
|
local rName, rGroup, rClass, GUID;
|
|
local CaheID = 1; -- make an ordered table
|
|
local excluded = 0;
|
|
local playerPrio = 900;
|
|
|
|
-- Cache the raid roster info eliminating useless info and already listed members
|
|
for i = 1, MAX_RAID_MEMBERS do
|
|
rName, _, rGroup, _, _, rClass = GetRaidRosterInfo(i);
|
|
GUID = UnitToGUID["raid"..i];
|
|
|
|
-- add all except member to skip
|
|
if not IsInSkipList(GUID, rGroup, DC.ClassUNameToNum[rClass]) then
|
|
|
|
if (rName) then -- (at log-in GetRaidRosterInfo() returns garbage)
|
|
|
|
if (not RaidRosterCache[CaheID]) then
|
|
RaidRosterCache[CaheID] = {};
|
|
end
|
|
|
|
RaidRosterCache[CaheID].rName = rName;
|
|
RaidRosterCache[CaheID].rGroup = rGroup;
|
|
RaidRosterCache[CaheID].rClass = rClass;
|
|
RaidRosterCache[CaheID].rIndex = i;
|
|
RaidRosterCache[CaheID].rGUID = GUID;
|
|
CaheID = CaheID + 1;
|
|
end
|
|
else
|
|
excluded = excluded + 1;
|
|
end
|
|
|
|
-- find our group (a whole iteration is required, raid info are not ordered) -- wrong, the player is always the last now but never trust Blizzard...
|
|
if currentGroup==0 and GUID == MyGUID then -- anyway they do the same thing in PlayerFrame.lua...
|
|
currentGroup = rGroup;
|
|
playerPrio = GetUnitPriority ("player", i, rGroup, rClass, false);
|
|
end
|
|
|
|
if CaheID + excluded > raidnum then -- we found all the units
|
|
RaidRosterCache[CaheID] = false;
|
|
break;
|
|
end
|
|
end
|
|
|
|
-- Add the player to the main list if needed
|
|
if (not IsInSkipOrPriorList(MyGUID, currentGroup, DC.ClassUNameToNum[DC.MyClass])) then
|
|
SortingTable["player"] = 900;
|
|
Status.Unit_Array_GUIDToUnit[MyGUID] = "player";
|
|
else -- well let's see if people complains that they cannot exclude themself...
|
|
SortingTable["player"] = playerPrio;
|
|
Status.Unit_Array_GUIDToUnit[MyGUID] = "player";
|
|
end
|
|
|
|
-- Now we have a cache without the units we want to skip
|
|
local TempID;
|
|
for _, raidMember in ipairs(RaidRosterCache) do
|
|
|
|
if not raidMember then break; end;
|
|
|
|
-- put each raid member with the right priority in our sorting table
|
|
if not Status.Unit_Array_GUIDToUnit[raidMember.rGUID] then
|
|
|
|
TempID = "raid"..raidMember.rIndex;
|
|
|
|
SortingTable[TempID] = GetUnitPriority (TempID, raidMember.rIndex, raidMember.rGroup, raidMember.rClass, false);
|
|
Status.Unit_Array_GUIDToUnit[raidMember.rGUID] = TempID;
|
|
end
|
|
|
|
if ( self.profile.Scan_Pets ) then
|
|
local pet = "";
|
|
pet = "raidpet"..raidMember.rIndex;
|
|
|
|
if ( UnitExists(pet) ) then
|
|
|
|
pGUID = UnitToGUID[pet];
|
|
|
|
if (not pGUID) then -- at logon sometimes pGUID is nil...
|
|
pGUID = pet;
|
|
end
|
|
|
|
-- add it only if not already in (could be the player pet...)
|
|
if (not Status.Unit_Array_GUIDToUnit[pGUID]) then
|
|
SortingTable[pet] = GetUnitPriority (pet, raidMember.rIndex, raidMember.rGroup, (select(2,UnitClass(pet))), true);
|
|
Status.Unit_Array_GUIDToUnit[pGUID] = pet;
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end -- END if we are in a raid
|
|
|
|
-- NEW focus management
|
|
-- there is a focus and its not hostile in the first place
|
|
if UnitExists("focus") and (not UnitCanAttack("focus", "player") or UnitIsFriend("focus", "player")) then
|
|
pGUID = UnitToGUID["focus"]
|
|
-- the unit is not registered somewhere else yet
|
|
if not Status.Unit_Array_GUIDToUnit[pGUID] then
|
|
SortingTable["focus"] = -1; -- add it at the end...
|
|
Status.Unit_Array_GUIDToUnit[pGUID] = "focus";
|
|
end
|
|
end
|
|
|
|
-- we use a hash-key style table for Status.Unit_Array_GUIDToUnit because it allows us
|
|
-- to not care if we add a same unit several times (speed optimization)
|
|
-- but we cannot use sort unless indexes are integer so:
|
|
Status.Unit_Array = {}
|
|
local GUID;
|
|
for GUID, unit in pairs(Status.Unit_Array_GUIDToUnit) do -- /!\ PAIRS not iPAIRS
|
|
t_insert(Status.Unit_Array, unit);
|
|
|
|
Status.Unit_Array_UnitToGUID[unit] = GUID; -- just a useful table, not used here :)
|
|
end
|
|
|
|
table.sort(Status.Unit_Array, function (a,b)
|
|
if (not (SortingTable[a] < 0 and SortingTable[b] < 0)) then -- one of the values is > 0
|
|
return SortingTable[b] < SortingTable[a];
|
|
else -- both are < 0
|
|
return SortingTable[a] < SortingTable[b];
|
|
end
|
|
end);
|
|
|
|
|
|
Status.UnitNum = #Status.Unit_Array;
|
|
|
|
UnitToGUID = {};
|
|
GUIDToUnit = {};
|
|
D.Status.GroupUpdatedOn = D:NiceTime(); -- It's used in UNIT_AURA event handler to trigger a rescan if the array is found inacurate
|
|
|
|
self:Debug ("|cFFFF44FF-->|r Update complete!", Status.UnitNum);
|
|
return;
|
|
end
|
|
|
|
function D:GetFakeUnit_array ()
|
|
|
|
if not D.Status.TestLayout then
|
|
return;
|
|
end
|
|
|
|
self:Debug ("|cFFFF22FF-->|r Creating fake Units Array");
|
|
|
|
local Status = self.Status;
|
|
Status.Unit_Array_GUIDToUnit[DC.MyGUID] = "player";
|
|
|
|
Status.Unit_Array = {}
|
|
|
|
for i = 1, D.Status.TestLayoutUNum - 1 do -- the player is always in so we remove one here.
|
|
Status.Unit_Array_GUIDToUnit["raid" .. i .. "GUID"] = "raid" .. i;
|
|
end
|
|
|
|
local GUID;
|
|
for GUID, unit in pairs(Status.Unit_Array_GUIDToUnit) do -- /!\ PAIRS not iPAIRS
|
|
t_insert(Status.Unit_Array, unit);
|
|
|
|
Status.Unit_Array_UnitToGUID[unit] = GUID; -- just a useful table, not used here :)
|
|
end
|
|
|
|
table.sort(Status.Unit_Array);
|
|
|
|
Status.UnitNum = #Status.Unit_Array;
|
|
D.Status.GroupUpdatedOn = D:NiceTime(); -- It's used in UNIT_AURA event handler to trigger a rescan if the array is found inacurate
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--}}}
|
|
|
|
-------------------------------------------------------------------------------
|
|
T._LoadedFiles["Dcr_Raid.lua"] = "2.5.1-6-gd3885c5";
|
|
|
|
-- "Your God is dead and no one cares"
|
|
-- "If there is a Hell I'll see you there"
|