32324ff732
Three gaps closed for CoA custom-class players:
1. DCR_init.lua C_Player:IsCustomClass() branches were stubs printing
"CoA is not currently supported". Filled both branches (SpellsToUse +
Spells dictionary) with 11 dispel spell IDs covering 10 CoA classes
(Chronomancer, Cultist, Templar, Venomancer, Pyromancer, Ranger,
Bloodmage, Runemaster, Starcaller, Witch Hunter). The other 11 CoA
classes have no dedicated player-cast dispel in coa-db.
2. Dcr_Raid.lua ClassNumTo{LName,UName} were hardcoded to indices
11..21 (vanilla 10 + HERO). Append every additional CLASS_SORT_ORDER
token starting at 22 — append-only so existing DecursiveDB skip /
priority numeric keys stay valid. CoA-class units in raids now get
priority/skip lookups instead of silent nil-guarded no-ops.
3. Bumped toc Version to Asc-1.1.0-coa.
Spell IDs sourced from coa-db (mind_of_ascension_talent + class_spell)
filtered to effect_id=38 (DISPEL) with misc_value in {1,2,3,4} (Magic,
Curse, Disease, Poison).
PopulateListFrame XML buttons (Dcr_lists.xml) for the 21 CoA classes
deferred — needs UI rework (frame is already near-full at 11 buttons).
Skip/priority lists still work without these populate-by-class
shortcuts.
812 lines
28 KiB
Lua
812 lines
28 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.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,
|
|
}
|
|
|
|
-- CoA: append every RAID_CLASS_COLORS entry not already mapped above (idx 22+).
|
|
-- Iterate CLASS_SORT_ORDER for stable ordering across sessions; fall back to
|
|
-- pairs() only if CLASS_SORT_ORDER is unavailable. Append-only preserves the
|
|
-- numeric keys baked into DecursiveDB skip/priority lists from older configs.
|
|
do
|
|
local existing = {}
|
|
for _, v in pairs(DC.ClassNumToUName) do existing[v] = true end
|
|
|
|
local order = _G.CLASS_SORT_ORDER
|
|
if not order then
|
|
order = {}
|
|
for class in pairs(_G.RAID_CLASS_COLORS or {}) do
|
|
order[#order + 1] = class
|
|
end
|
|
end
|
|
|
|
local idx = 22
|
|
for _, class in ipairs(order) do
|
|
if not existing[class] then
|
|
DC.ClassNumToLName[idx] = LC[class] or class
|
|
DC.ClassNumToUName[idx] = class
|
|
existing[class] = true
|
|
idx = idx + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
DC.ClassLNameToNum = D:tReverse(DC.ClassNumToLName);
|
|
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"
|