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.
636 lines
17 KiB
636 lines
17 KiB
|
2 years ago
|
local _;
|
||
|
|
|
||
|
|
|
||
|
|
-- for saving once learnt yards in saved variables
|
||
|
|
local VUHDO_STORED_ZONES = { };
|
||
|
|
local VUHDO_CLUSTER_BLACKLIST = { };
|
||
|
|
local VUHDO_RAID = {};
|
||
|
|
|
||
|
|
local sqrt = sqrt;
|
||
|
|
local CheckInteractDistance = CheckInteractDistance;
|
||
|
|
local WorldMapFrame = WorldMapFrame;
|
||
|
|
local GetMouseFocus = GetMouseFocus;
|
||
|
|
local pairs = pairs;
|
||
|
|
local GetTime = GetTime;
|
||
|
|
local GetSpellCooldown = GetSpellCooldown;
|
||
|
|
local twipe = table.wipe;
|
||
|
|
local tsort = table.sort;
|
||
|
|
local VUHDO_setMapToCurrentZone;
|
||
|
|
local VUHDO_tableUniqueAdd;
|
||
|
|
|
||
|
|
local VUHDO_COORD_DELTAS = { };
|
||
|
|
setmetatable(VUHDO_COORD_DELTAS, VUHDO_META_NEW_ARRAY);
|
||
|
|
|
||
|
|
local VUHDO_MAP_WIDTH = 0;
|
||
|
|
local VUHDO_LAST_ZONE = nil;
|
||
|
|
|
||
|
|
local VUHDO_MIN_TICK_UNIT = 0.000000000001;
|
||
|
|
local VUHDO_MAX_TICK_UNIT = 1;
|
||
|
|
local VUHDO_MAP_LIMIT_YARDS = 1000000;
|
||
|
|
local VUHDO_MAX_SAMPLES = 50;
|
||
|
|
local VUHDO_MAX_ITERATIONS = 120; -- For a 40 man raid there is a total of +800 iterations
|
||
|
|
|
||
|
|
--
|
||
|
|
local VUHDO_CLUSTER_BASE_RAID = { };
|
||
|
|
function VUHDO_clusterBuilderInitLocalOverrides()
|
||
|
|
VUHDO_CLUSTER_BASE_RAID = _G["VUHDO_CLUSTER_BASE_RAID"];
|
||
|
|
VUHDO_RAID = _G["VUHDO_RAID"];
|
||
|
|
|
||
|
|
VUHDO_setMapToCurrentZone = _G["VUHDO_setMapToCurrentZone"];
|
||
|
|
VUHDO_tableUniqueAdd = _G["VUHDO_tableUniqueAdd"];
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local VUHDO_MAP_FIX_WIDTH = {
|
||
|
|
["AlteracValley"] = {
|
||
|
|
[1] = 4237.49987792969,
|
||
|
|
},
|
||
|
|
|
||
|
|
--[[["StormwindCity"] = {
|
||
|
|
[0] = 1737.4999589920044,
|
||
|
|
},]]
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
-- Inspect, Trade, Duel, UnitInRange(, UnitIsVisible? => doesn't seem to be reliable)
|
||
|
|
local VUHDO_INTERACT_MAX_DISTANCES = { VUHDO_MIN_TICK_UNIT, VUHDO_MIN_TICK_UNIT, VUHDO_MIN_TICK_UNIT, VUHDO_MIN_TICK_UNIT };
|
||
|
|
local VUHDO_INTERACT_FAIL_MIN_DISTANCES = { VUHDO_MAX_TICK_UNIT, VUHDO_MAX_TICK_UNIT, VUHDO_MAX_TICK_UNIT, VUHDO_MAX_TICK_UNIT };
|
||
|
|
local VUHDO_INTERACT_YARDS = { 28, 11.11, 9.9, 40 };
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local function VUHDO_clusterBuilderStoreZone(aZone)
|
||
|
|
if aZone then
|
||
|
|
VUHDO_STORED_ZONES[aZone] = { };
|
||
|
|
VUHDO_STORED_ZONES[aZone]["good"] = VUHDO_deepCopyTable(VUHDO_INTERACT_MAX_DISTANCES);
|
||
|
|
VUHDO_STORED_ZONES[aZone]["fail"] = VUHDO_deepCopyTable(VUHDO_INTERACT_FAIL_MIN_DISTANCES);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tIsValid;
|
||
|
|
local function VUHDO_isValidClusterUnit(anInfo)
|
||
|
|
tIsValid = not anInfo["dead"] and anInfo["connected"] and anInfo["visible"];
|
||
|
|
VUHDO_CLUSTER_BLACKLIST[anInfo["unit"]] = not tIsValid;
|
||
|
|
return tIsValid;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tDistance;
|
||
|
|
local tEmptyUnit = { };
|
||
|
|
local function VUHDO_calibrateMapScale(aUnit, aDeltaX, aDeltaY)
|
||
|
|
tDistance = sqrt((aDeltaX * aDeltaX) + ((aDeltaY * 0.6666666666666) ^ 2));
|
||
|
|
|
||
|
|
for tCnt = 1, 3 do
|
||
|
|
-- Check only if new distance is within bandwidth (= better result than before)
|
||
|
|
if tDistance > VUHDO_INTERACT_MAX_DISTANCES[tCnt] and tDistance < VUHDO_INTERACT_FAIL_MIN_DISTANCES[tCnt] then
|
||
|
|
if CheckInteractDistance(aUnit, tCnt) then
|
||
|
|
VUHDO_INTERACT_MAX_DISTANCES[tCnt] = tDistance;
|
||
|
|
else
|
||
|
|
VUHDO_INTERACT_FAIL_MIN_DISTANCES[tCnt] = tDistance;
|
||
|
|
end
|
||
|
|
VUHDO_clusterBuilderStoreZone(VUHDO_LAST_ZONE);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if tDistance > VUHDO_INTERACT_MAX_DISTANCES[4] and tDistance < VUHDO_INTERACT_FAIL_MIN_DISTANCES[4] then
|
||
|
|
if (VUHDO_RAID[aUnit] or tEmptyUnit)["baseRange"] then
|
||
|
|
VUHDO_INTERACT_MAX_DISTANCES[4] = tDistance;
|
||
|
|
else
|
||
|
|
VUHDO_INTERACT_FAIL_MIN_DISTANCES[4] = tDistance;
|
||
|
|
end
|
||
|
|
VUHDO_clusterBuilderStoreZone(VUHDO_LAST_ZONE);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tCurrWorldSize, tMinWorldSize, tUpperBoundary;
|
||
|
|
local function VUHDO_getHeuristicMapWidth()
|
||
|
|
tMinWorldSize = VUHDO_MAP_LIMIT_YARDS;
|
||
|
|
tUpperBoundary = nil;
|
||
|
|
for tIndex, tNormFactor in pairs(VUHDO_INTERACT_YARDS) do
|
||
|
|
tCurrWorldSize = tNormFactor / VUHDO_INTERACT_MAX_DISTANCES[tIndex]; -- yards per full tick = world size in yards
|
||
|
|
|
||
|
|
if tCurrWorldSize < tMinWorldSize then -- Better test results are always smaller = closer to the limit of interact distance
|
||
|
|
tMinWorldSize = tCurrWorldSize;
|
||
|
|
if VUHDO_INTERACT_FAIL_MIN_DISTANCES[tIndex] < VUHDO_MAX_TICK_UNIT then
|
||
|
|
tUpperBoundary = tNormFactor / VUHDO_INTERACT_FAIL_MIN_DISTANCES[tIndex];
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return tUpperBoundary and (tMinWorldSize + tUpperBoundary) * 0.5 or tMinWorldSize;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tX1, tY1, tX2, tY2;
|
||
|
|
local tIsValid;
|
||
|
|
local tIsInInstance;
|
||
|
|
local function VUHDO_determineDistanceBetween(aUnit, anotherUnit)
|
||
|
|
-- as of patch 7.1 APIs related to unit position/distance do not function inside instances
|
||
|
|
tIsInInstance, _ = IsInInstance();
|
||
|
|
|
||
|
|
if tIsInInstance then
|
||
|
|
return nil, nil;
|
||
|
|
end
|
||
|
|
|
||
|
|
tIsValid = true;
|
||
|
|
|
||
|
|
-- as of patch 7.1 GetPlayerMapPosition() returns zero/nil inside certain zones
|
||
|
|
tX1, tY1 = VUHDO_getUnitMapPosition(aUnit);
|
||
|
|
if not tX1 or (tX1 + tY1 <= 0) then
|
||
|
|
VUHDO_CLUSTER_BLACKLIST[aUnit] = true;
|
||
|
|
tIsValid = false;
|
||
|
|
end
|
||
|
|
|
||
|
|
-- as of patch 7.1 GetPlayerMapPosition() returns zero/nil inside certain zones
|
||
|
|
tX2, tY2 = VUHDO_getUnitMapPosition(anotherUnit);
|
||
|
|
if not tX2 or (tX2 + tY2 <= 0) then
|
||
|
|
VUHDO_CLUSTER_BLACKLIST[anotherUnit] = true;
|
||
|
|
tIsValid = false;
|
||
|
|
end
|
||
|
|
|
||
|
|
if not tIsValid then
|
||
|
|
return nil, nil;
|
||
|
|
end
|
||
|
|
|
||
|
|
return tX1 - tX2, tY1 - tY2;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local function VUHDO_clusterBuilderNewZone(anOldZone, aNewZone)
|
||
|
|
VUHDO_clusterBuilderStoreZone(anOldZone);
|
||
|
|
|
||
|
|
if VUHDO_STORED_ZONES[aNewZone] then
|
||
|
|
VUHDO_INTERACT_MAX_DISTANCES = VUHDO_deepCopyTable(VUHDO_STORED_ZONES[aNewZone]["good"]);
|
||
|
|
VUHDO_INTERACT_FAIL_MIN_DISTANCES = VUHDO_deepCopyTable(VUHDO_STORED_ZONES[aNewZone]["fail"]);
|
||
|
|
else
|
||
|
|
VUHDO_INTERACT_MAX_DISTANCES[1] = VUHDO_MIN_TICK_UNIT;
|
||
|
|
VUHDO_INTERACT_MAX_DISTANCES[2] = VUHDO_MIN_TICK_UNIT;
|
||
|
|
VUHDO_INTERACT_MAX_DISTANCES[3] = VUHDO_MIN_TICK_UNIT;
|
||
|
|
VUHDO_INTERACT_MAX_DISTANCES[4] = VUHDO_MIN_TICK_UNIT;
|
||
|
|
VUHDO_INTERACT_FAIL_MIN_DISTANCES[1] = VUHDO_MAX_TICK_UNIT;
|
||
|
|
VUHDO_INTERACT_FAIL_MIN_DISTANCES[2] = VUHDO_MAX_TICK_UNIT;
|
||
|
|
VUHDO_INTERACT_FAIL_MIN_DISTANCES[3] = VUHDO_MAX_TICK_UNIT;
|
||
|
|
VUHDO_INTERACT_FAIL_MIN_DISTANCES[4] = VUHDO_MAX_TICK_UNIT;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tUnit, tInfo;
|
||
|
|
local tAnotherUnit, tAnotherInfo;
|
||
|
|
local tX, tY, tDeltaX, tDeltaY;
|
||
|
|
local tMaxX, tMaxY;
|
||
|
|
local tMapId, tMap, tMapFileName, tDungeonLevels, tCurrLevel;
|
||
|
|
local tCurrentZone;
|
||
|
|
local tNumRaid;
|
||
|
|
local tIndex = 0;
|
||
|
|
local tNumSamples, tNumIterations;
|
||
|
|
local tIsInInstance;
|
||
|
|
local VuhDoDummyStub = {
|
||
|
|
["GetName"] = function() return ""; end,
|
||
|
|
["IsForbidden"] = function() return false; end,
|
||
|
|
};
|
||
|
|
|
||
|
|
function VUHDO_updateAllClusters()
|
||
|
|
|
||
|
|
-- as of patch 7.1 APIs related to unit position/distance do not function inside instances
|
||
|
|
tIsInInstance, _ = IsInInstance();
|
||
|
|
|
||
|
|
if tIsInInstance then
|
||
|
|
return;
|
||
|
|
end
|
||
|
|
|
||
|
|
-- @UGLY Carbonite workaround
|
||
|
|
local tFocusFrame = GetMouseFocus() or VuhDoDummyStub;
|
||
|
|
|
||
|
|
-- check if our mouse focus frame is forbidden before calling any methods on it
|
||
|
|
if tFocusFrame:IsForbidden() then
|
||
|
|
return;
|
||
|
|
elseif not tFocusFrame:GetName() then
|
||
|
|
return;
|
||
|
|
end
|
||
|
|
|
||
|
|
if WorldMapFrame:IsShown() then
|
||
|
|
return;
|
||
|
|
end
|
||
|
|
|
||
|
|
-- TODO: is this needed anymore given 8.0.1 map changes?
|
||
|
|
--[[tX, tY = VUHDO_getUnitMapPosition("player");
|
||
|
|
if (tX or 0) + (tY or 0) <= 0 then
|
||
|
|
-- FIXME: calling WorldMapFrame:SetMapID produces strange results as of build 26567
|
||
|
|
VUHDO_setMapToCurrentZone();
|
||
|
|
end]]
|
||
|
|
|
||
|
|
-- In 8.0.1 Blizzard introduced new C_Map APIs
|
||
|
|
-- each map level has a unique map ID now
|
||
|
|
-- tMapFileName will now represent simply the map name
|
||
|
|
-- tCurrLevel will now represent the unique map ID
|
||
|
|
-- tDungeonLevels will still group all map IDs under the same map name (e.g. old map levels)
|
||
|
|
tMapId = C_Map.GetBestMapForUnit("player");
|
||
|
|
|
||
|
|
if tMapId then
|
||
|
|
tMap = C_Map.GetMapInfo(tMapId);
|
||
|
|
end
|
||
|
|
|
||
|
|
tMapFileName = tMap and tMap["name"] or "*";
|
||
|
|
tCurrLevel = tMap and tMap["mapID"] or 0;
|
||
|
|
tCurrentZone = tMapFileName .. tCurrLevel;
|
||
|
|
|
||
|
|
if VUHDO_LAST_ZONE ~= tCurrentZone then
|
||
|
|
VUHDO_clusterBuilderNewZone(VUHDO_LAST_ZONE, tCurrentZone);
|
||
|
|
VUHDO_LAST_ZONE = tCurrentZone;
|
||
|
|
end
|
||
|
|
|
||
|
|
tNumSamples, tNumIterations = 0, 0;
|
||
|
|
tNumRaid = #VUHDO_CLUSTER_BASE_RAID;
|
||
|
|
|
||
|
|
while true do
|
||
|
|
tIndex = tIndex + 1;
|
||
|
|
if tIndex > tNumRaid then
|
||
|
|
tIndex = 0;
|
||
|
|
break;
|
||
|
|
end
|
||
|
|
|
||
|
|
tInfo = VUHDO_CLUSTER_BASE_RAID[tIndex];
|
||
|
|
tUnit = tInfo["unit"];
|
||
|
|
|
||
|
|
if VUHDO_isValidClusterUnit(tInfo) then
|
||
|
|
for tCnt = tIndex + 1, tNumRaid do
|
||
|
|
tAnotherInfo = VUHDO_CLUSTER_BASE_RAID[tCnt];
|
||
|
|
|
||
|
|
if VUHDO_isValidClusterUnit(tAnotherInfo) then
|
||
|
|
tAnotherUnit = tAnotherInfo["unit"];
|
||
|
|
tDeltaX, tDeltaY = VUHDO_determineDistanceBetween(tUnit, tAnotherUnit);
|
||
|
|
|
||
|
|
if tDeltaX then
|
||
|
|
if not VUHDO_COORD_DELTAS[tUnit][tAnotherUnit] then
|
||
|
|
VUHDO_COORD_DELTAS[tUnit][tAnotherUnit] = { };
|
||
|
|
end
|
||
|
|
VUHDO_COORD_DELTAS[tUnit][tAnotherUnit][1] = tDeltaX;
|
||
|
|
VUHDO_COORD_DELTAS[tUnit][tAnotherUnit][2] = tDeltaY;
|
||
|
|
|
||
|
|
-- and the other way round to reduce iterations
|
||
|
|
if not VUHDO_COORD_DELTAS[tAnotherUnit] then
|
||
|
|
VUHDO_COORD_DELTAS[tAnotherUnit] = { };
|
||
|
|
end
|
||
|
|
if not VUHDO_COORD_DELTAS[tAnotherUnit][tUnit] then
|
||
|
|
VUHDO_COORD_DELTAS[tAnotherUnit][tUnit] = { };
|
||
|
|
end
|
||
|
|
VUHDO_COORD_DELTAS[tAnotherUnit][tUnit][1] = tDeltaX;
|
||
|
|
VUHDO_COORD_DELTAS[tAnotherUnit][tUnit][2] = tDeltaY;
|
||
|
|
|
||
|
|
tNumSamples = tNumSamples + 1;
|
||
|
|
if tNumSamples > 50 then break; end -- VUHDO_MAX_SAMPLES
|
||
|
|
end
|
||
|
|
end
|
||
|
|
tNumIterations = tNumIterations + 1;
|
||
|
|
if tNumIterations > 120 then break; end -- VUHDO_MAX_ITERATIONS
|
||
|
|
end -- for
|
||
|
|
else -- Blacklist updaten
|
||
|
|
for tCnt = tIndex + 1, tNumRaid do
|
||
|
|
tAnotherInfo = VUHDO_CLUSTER_BASE_RAID[tCnt];
|
||
|
|
if not tAnotherInfo then break; end
|
||
|
|
VUHDO_isValidClusterUnit(tAnotherInfo);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if tNumSamples > 50 or tNumIterations > 120 then break; end -- VUHDO_MAX_SAMPLES -- VUHDO_MAX_ITERATIONS
|
||
|
|
end
|
||
|
|
|
||
|
|
tMaxX = nil;
|
||
|
|
|
||
|
|
-- Try to determine well known dungeons
|
||
|
|
tDungeonLevels = VUHDO_MAP_FIX_WIDTH[tMapFileName];
|
||
|
|
if tDungeonLevels then
|
||
|
|
tMaxX = tDungeonLevels[tCurrLevel];
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Otherwise get from heuristic database
|
||
|
|
if (tMaxX or 0) == 0 then
|
||
|
|
if VUHDO_COORD_DELTAS["player"] then
|
||
|
|
for tUnit, tDeltas in pairs(VUHDO_COORD_DELTAS["player"]) do
|
||
|
|
VUHDO_calibrateMapScale(tUnit, tDeltas[1], tDeltas[2]);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
tMaxX = VUHDO_getHeuristicMapWidth();
|
||
|
|
|
||
|
|
-- Unreasonable?
|
||
|
|
if tMaxX < 1 or tMaxX >= VUHDO_MAP_LIMIT_YARDS then
|
||
|
|
VUHDO_MAP_WIDTH = 0;
|
||
|
|
return;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- if (VUHDO_MAP_WIDTH ~= tMaxX) then
|
||
|
|
-- VUHDO_Msg("Map approx yards changed from " .. floor(VUHDO_MAP_WIDTH * 10) / 10 .. " to " .. floor(tMaxX * 10) / 10);
|
||
|
|
-- end
|
||
|
|
|
||
|
|
VUHDO_MAP_WIDTH = tMaxX;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
function VUHDO_resetClusterCoordDeltas()
|
||
|
|
twipe(VUHDO_COORD_DELTAS);
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local function VUHDO_sortClusterComparator(aUnit, anotherUnit)
|
||
|
|
return VUHDO_RAID[aUnit]["healthmax"] - VUHDO_RAID[aUnit]["health"]
|
||
|
|
> VUHDO_RAID[anotherUnit]["healthmax"] - VUHDO_RAID[anotherUnit]["health"];
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tDistance, tNumber, tInfo;
|
||
|
|
local tStart, tDuration;
|
||
|
|
function VUHDO_getUnitsInRadialClusterWith(aUnit, aYardsPow, anArray, aCdSpell)
|
||
|
|
twipe(anArray);
|
||
|
|
|
||
|
|
if aCdSpell then
|
||
|
|
tStart, tDuration = GetSpellCooldown(aCdSpell);
|
||
|
|
tDuration = tDuration or 0;
|
||
|
|
|
||
|
|
if tDuration > 1.5 then -- Don't remove clusters for gcd
|
||
|
|
tStart = tStart or 0;
|
||
|
|
if tStart + tDuration > GetTime() then
|
||
|
|
return anArray;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
tInfo = VUHDO_RAID[aUnit];
|
||
|
|
if tInfo and not VUHDO_CLUSTER_BLACKLIST[aUnit] then
|
||
|
|
anArray[1] = aUnit;-- Source is always part of the cluster
|
||
|
|
end
|
||
|
|
if VUHDO_MAP_WIDTH == 0 or not VUHDO_COORD_DELTAS[aUnit] then
|
||
|
|
return anArray;
|
||
|
|
end
|
||
|
|
|
||
|
|
for tOtherUnit, tDeltas in pairs(VUHDO_COORD_DELTAS[aUnit]) do
|
||
|
|
tDistance = (((tDeltas[1] or 0) * VUHDO_MAP_WIDTH) ^ 2) + (((tDeltas[2] or 0) * VUHDO_MAP_WIDTH / 1.5) ^ 2);
|
||
|
|
if tDistance <= aYardsPow and not VUHDO_CLUSTER_BLACKLIST[tOtherUnit] then
|
||
|
|
anArray[#anArray + 1] = tOtherUnit;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
tsort(anArray, VUHDO_sortClusterComparator);
|
||
|
|
return anArray;
|
||
|
|
end
|
||
|
|
local VUHDO_getUnitsInRadialClusterWith = VUHDO_getUnitsInRadialClusterWith;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tWinnerUnit, tInfo, tWinnerMissLife;
|
||
|
|
local tCurrMissLife;
|
||
|
|
local function VUHDO_getMostDeficitUnitOutOf(anIncludeList, anExcludeList)
|
||
|
|
tWinnerUnit = nil;
|
||
|
|
tWinnerMissLife = -1;
|
||
|
|
|
||
|
|
for _, tUnit in pairs(anIncludeList) do
|
||
|
|
if not anExcludeList[tUnit] then
|
||
|
|
tInfo = VUHDO_RAID[tUnit];
|
||
|
|
if tInfo and tInfo["healthmax"] - tInfo["health"] > tWinnerMissLife then
|
||
|
|
tWinnerUnit = tUnit;
|
||
|
|
tWinnerMissLife = tInfo["healthmax"] - tInfo["health"];
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return tWinnerUnit;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tNextJumps = { };
|
||
|
|
local tExcludeList = { };
|
||
|
|
local tNumJumps = 0;
|
||
|
|
function VUHDO_getUnitsInChainClusterWith(aUnit, aYardsPow, anArray, aMaxTargets, aCdSpell)
|
||
|
|
twipe(anArray);
|
||
|
|
twipe(tExcludeList)
|
||
|
|
for tCnt = 1, aMaxTargets do
|
||
|
|
anArray[tCnt] = aUnit;
|
||
|
|
tExcludeList[aUnit] = true;
|
||
|
|
VUHDO_getUnitsInRadialClusterWith(aUnit, aYardsPow, tNextJumps, aCdSpell);
|
||
|
|
aUnit = VUHDO_getMostDeficitUnitOutOf(tNextJumps, tExcludeList);
|
||
|
|
if not aUnit then break; end
|
||
|
|
end
|
||
|
|
return anArray;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tDeltas, tDistance;
|
||
|
|
function VUHDO_getDistanceBetween(aUnit, anotherUnit)
|
||
|
|
if VUHDO_CLUSTER_BLACKLIST[aUnit] or VUHDO_CLUSTER_BLACKLIST[anotherUnit] then return nil; end
|
||
|
|
|
||
|
|
if VUHDO_COORD_DELTAS[aUnit] and VUHDO_COORD_DELTAS[aUnit][anotherUnit] then
|
||
|
|
tDeltas = VUHDO_COORD_DELTAS[aUnit][anotherUnit];
|
||
|
|
return sqrt((((tDeltas[1] or 0) * VUHDO_MAP_WIDTH) ^ 2) + (((tDeltas[2] or 0) * VUHDO_MAP_WIDTH / 1.5) ^ 2));
|
||
|
|
end
|
||
|
|
|
||
|
|
return nil;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tDeltas, tXCoord, tYCoord;
|
||
|
|
local function VUHDO_getRealPosition(aUnit)
|
||
|
|
if VUHDO_CLUSTER_BLACKLIST[aUnit] then return nil; end
|
||
|
|
|
||
|
|
if VUHDO_COORD_DELTAS[aUnit] then
|
||
|
|
tXCoord, tYCoord = VUHDO_getUnitMapPosition(aUnit);
|
||
|
|
if tXCoord and tYCoord then
|
||
|
|
return tXCoord * VUHDO_MAP_WIDTH, tYCoord * VUHDO_MAP_WIDTH / 1.5;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return nil;
|
||
|
|
end
|
||
|
|
|
||
|
|
--------------------------------------------------------------------------------------------------
|
||
|
|
|
||
|
|
local VuhDoLine = { };
|
||
|
|
local sLines = { };
|
||
|
|
VuhDoLine.__index = VuhDoLine;
|
||
|
|
|
||
|
|
--
|
||
|
|
local tLine;
|
||
|
|
function VuhDoLine.create(aLineNum, aStartX, aStartY, anEndX, anEndY)
|
||
|
|
--local tLine = { };
|
||
|
|
if (sLines[aLineNum] == nil) then
|
||
|
|
sLines[aLineNum] = { };
|
||
|
|
setmetatable(sLines[aLineNum], VuhDoLine);
|
||
|
|
end
|
||
|
|
tLine = sLines[aLineNum];
|
||
|
|
|
||
|
|
tLine.startX, tLine.startY, tLine.endX, tLine.endY
|
||
|
|
= aStartX, aStartY, anEndX, anEndY;
|
||
|
|
return tLine;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
function VuhDoLine:enthaelt(anX, anY)
|
||
|
|
return (anX >= self.startX and anX <= self.endX) or (anX <= self.startX and anX >= self.endX);
|
||
|
|
end
|
||
|
|
|
||
|
|
function VuhDoLine:hoehe()
|
||
|
|
return self.endY - self.startY;
|
||
|
|
end
|
||
|
|
|
||
|
|
function VuhDoLine:breite()
|
||
|
|
return self.endX - self.startX;
|
||
|
|
end
|
||
|
|
|
||
|
|
function VuhDoLine:steigung()
|
||
|
|
return self:hoehe() / self:breite();
|
||
|
|
end
|
||
|
|
|
||
|
|
function VuhDoLine:laenge()
|
||
|
|
return sqrt((self:hoehe() * self:hoehe()) + (self:breite() * self:breite()));
|
||
|
|
end
|
||
|
|
|
||
|
|
function VuhDoLine:achsenabschnitt()
|
||
|
|
return self.startY - (self:steigung() * self.startX);
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
local tX;
|
||
|
|
function VuhDoLine:schnittpunkt(aLine)
|
||
|
|
tX = (aLine:achsenabschnitt() - self:achsenabschnitt()) / (self:steigung() - aLine:steigung());
|
||
|
|
return tX, self:steigung() * tX + self:achsenabschnitt();
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tLineToTarget;
|
||
|
|
local tOrthogonale;
|
||
|
|
local tOrthoLaenge;
|
||
|
|
local tPlayerX, tPlayerY;
|
||
|
|
local tTargetX, tTargetY;
|
||
|
|
local tZuPruefenX, tZuPruefenY;
|
||
|
|
local tSchnittX, tSchnittY;
|
||
|
|
local tDestCluster = { };
|
||
|
|
local tNumFound;
|
||
|
|
local tUnit;
|
||
|
|
function VUHDO_getUnitsInLinearCluster(aUnit, anArray, aRange, aMaxTargets, anIsHealsPlayer, aCdSpell)
|
||
|
|
twipe(anArray);
|
||
|
|
twipe(tDestCluster);
|
||
|
|
|
||
|
|
if aCdSpell then
|
||
|
|
tStart, tDuration = GetSpellCooldown(aCdSpell);
|
||
|
|
tDuration = tDuration or 0;
|
||
|
|
|
||
|
|
if tDuration > 1.5 then -- Don't remove clusters for gcd
|
||
|
|
tStart = tStart or 0;
|
||
|
|
if tStart + tDuration > GetTime() then
|
||
|
|
return anArray;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if VUHDO_MAP_WIDTH == 0 or not VUHDO_COORD_DELTAS[aUnit] then return; end
|
||
|
|
|
||
|
|
tPlayerX, tPlayerY = VUHDO_getRealPosition("player");
|
||
|
|
if not tPlayerX then return; end
|
||
|
|
|
||
|
|
tTargetX, tTargetY = VUHDO_getRealPosition(aUnit);
|
||
|
|
if not tTargetX then return; end
|
||
|
|
|
||
|
|
tLineToTarget = VuhDoLine.create(1, tPlayerX, tPlayerY, tTargetX, tTargetY);
|
||
|
|
|
||
|
|
for _, tInfo in pairs(VUHDO_CLUSTER_BASE_RAID) do
|
||
|
|
tUnit = tInfo["unit"];
|
||
|
|
if "player" ~= tUnit and not VUHDO_CLUSTER_BLACKLIST[tUnit] then
|
||
|
|
tZuPruefenX, tZuPruefenY = VUHDO_getRealPosition(tUnit);
|
||
|
|
if tZuPruefenX then
|
||
|
|
|
||
|
|
tOrthogonale = VuhDoLine.create(2,
|
||
|
|
tZuPruefenX - tLineToTarget:hoehe(),
|
||
|
|
tZuPruefenY + tLineToTarget:breite(),
|
||
|
|
tZuPruefenX + tLineToTarget:hoehe(),
|
||
|
|
tZuPruefenY - tLineToTarget:breite());
|
||
|
|
|
||
|
|
tSchnittX, tSchnittY = tOrthogonale:schnittpunkt(tLineToTarget);
|
||
|
|
|
||
|
|
if tLineToTarget:enthaelt(tSchnittX, tSchnittY) then
|
||
|
|
tOrthoLaenge = VuhDoLine.create(3, tZuPruefenX, tZuPruefenY,
|
||
|
|
tSchnittX, tSchnittY);
|
||
|
|
if tOrthoLaenge:laenge() <= aRange then
|
||
|
|
tDestCluster[#tDestCluster + 1] = aUnit;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if anIsHealsPlayer then
|
||
|
|
if (VUHDO_tableUniqueAdd(tDestCluster, "player")) then
|
||
|
|
aMaxTargets = aMaxTargets + 1;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
tsort(tDestCluster, VUHDO_sortClusterComparator);
|
||
|
|
tNumFound = #tDestCluster;
|
||
|
|
for tCnt = 1, tNumFound > aMaxTargets and aMaxTargets or tNumFound do
|
||
|
|
anArray[tCnt] = tDestCluster[tCnt];
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
local tVector2d;
|
||
|
|
local tMapId;
|
||
|
|
function VUHDO_getUnitMapPosition(aUnit)
|
||
|
|
|
||
|
|
if not aUnit then
|
||
|
|
return;
|
||
|
|
end
|
||
|
|
|
||
|
|
-- 8.0.1 build 26567 added restrictions (must be in player's party) on which unit IDs can be queried
|
||
|
|
tMapId = C_Map.GetBestMapForUnit(aUnit) or C_Map.GetBestMapForUnit("player");
|
||
|
|
|
||
|
|
if not tMapId then
|
||
|
|
return;
|
||
|
|
end
|
||
|
|
|
||
|
|
tVector2d = C_Map.GetPlayerMapPosition(tMapId, aUnit);
|
||
|
|
|
||
|
|
if tVector2d then
|
||
|
|
return tVector2d:GetXY();
|
||
|
|
else
|
||
|
|
return nil, nil;
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|