vanilla-wow-addons – Rev 1
?pathlinks?
SA_LIST_BOXES = {};
-- TODO: incombat interval ja outofcombat interval! performance++ =)
SA_REFRESHRATE = 1.5;
SA_BASERATE = 0.6;
SA_INCREASE = 0.1; -- how much to decrease refresh rate per mob
SA_LASTREFRESH = SA_BASERATE;
SA_SEMIALERT = "|cffffa303";
SA_ALERTCOL = "|cffff0000";
SA_TANKCOL = "|cff00ff00";
-- title modes
MODE_OOC = 1;
MODE_NORMAL = 2;
MODE_FILTERED = 3;
MODE_PAUSED = 4;
MODE_NEAREST = 5;
MODE_OVERLOADED = 10;
-- contains all data from last update
SA_PREV = {
["aggro_count"] = 0,
["mob_count"] = 0,
["wb_count"] = 0,
["title_mode"] = -1,
["dirty"] = false
};
-- class icon texture coordinates
SA_TEXTCOORDS={};
SA_TEXTCOORDS["PRIEST"] = { left=0.50, right=0.75, top=0.25, bottom=0.50 };
SA_TEXTCOORDS["MAGE"] = { left=0.25, right=0.50, top=0.00, bottom=0.25 };
SA_TEXTCOORDS["WARLOCK"] = { left=0.75, right=1.00, top=0.25, bottom=0.50 };
SA_TEXTCOORDS["DRUID"] = { left=0.75, right=1.00, top=0.00, bottom=0.25 };
SA_TEXTCOORDS["HUNTER"] = { left=0.00, right=0.25, top=0.25, bottom=0.50 };
SA_TEXTCOORDS["ROGUE"] = { left=0.50, right=0.75, top=0.00, bottom=0.25 };
SA_TEXTCOORDS["WARRIOR"] = { left=0.00, right=0.25, top=0.00, bottom=0.25 };
SA_TEXTCOORDS["SHAMAN"] = { left=0.25, right=0.50, top=0.25, bottom=0.50 };
SA_TEXTCOORDS["PALADIN"] = { left=0.00, right=0.25, top=0.50, bottom=0.75 };
-- predefined icon locations
SA_ICONPOS={n=8};
SA_ICONPOS[1] = { name="Disabled", point="TOPLEFT", relativePoint="", x=-26, y=-28, width=25, height=25 };
SA_ICONPOS[2] = { name="Left bottom", point="TOPLEFT", relativePoint="", x=-26, y=-28, width=25, height=25 };
SA_ICONPOS[3] = { name="Left top", point="TOPLEFT", relativePoint="", x=-26, y=-3, width=25, height=25};
SA_ICONPOS[4] = { name="Inside box", point="BOTTOMRIGHT", relativePoint="", x=0, y=0, width=25, height=25};
SA_ICONPOS[5] = { name="Right bottom", point="TOPRIGHT", relativePoint="", x=26, y=-28, width=25, height=25 };
SA_ICONPOS[6] = { name="Right top", point="TOPRIGHT", relativePoint="", x=26, y=-3, width=25, height=25};
SA_ICONPOS[7] = { name="Left big", point="TOPLEFT", relativePoint="", x=-51, y=-3, width=50, height=50};
SA_ICONPOS[8] = { name="Right big", point="TOPRIGHT", relativePoint="", x=51, y=-3, width=50, height=50};
------------------------------------------------------------------------------
function SA_InitBar(bar, text)
bar:SetMinMaxValues(0, 100);
bar:SetValue(100);
text:SetHeight(12);
text:SetPoint("CENTER", bar:GetName(), "CENTER", 0, 0);
SetTextStatusBarText(bar, text);
ShowTextStatusBarText(bar);
end
function SA_List_OnLoad()
-- initialize boxes
for i=1, 10 do
local box = {};
box["frame"] = getglobal("Target"..i);
box["mobText"] = getglobal("Target"..i.."MobText");
box["targetText"] = getglobal("Target"..i.."TargetText");
box["targetOf"] = getglobal("Target"..i.."TargetOf");
box["mobBar"] = getglobal("Target"..i.."MobBar");
box["targetBar"] = getglobal("Target"..i.."TargetBar");
box["classIcon"] = getglobal("Target"..i.."ClassIcon");
box["targetIcon"] = getglobal("Target"..i.."TargetIcon");
box["huntersMarkIcon"] = getglobal("Target"..i.."HuntersMarkIcon");
SA_LIST_BOXES[i] = box;
end
end
function SA_List_OnShow()
-- TODO: this should be done only if options altered from xml defaults
SA_List_UpdateAppearance();
if (SA_OPTIONS.ListScale ~= 1.0) then
SAListFrameScaler:SetScale(SA_OPTIONS.ListScale);
end
-- set title button to correct mode
SA_List_SetTitleButton(MODE_OOC);
end
------------------------------------------------------------------------------
-- initialize list dropdown menu
------------------------------------------------------------------------------
function SA_List_FrameDropDown_OnLoad()
UIDropDownMenu_Initialize(this, SA_List_FrameDropDown_Initialize, "MENU");
end
------------------------------------------------------------------------------
-- note: this is called always when dropdown is shown!
------------------------------------------------------------------------------
function SA_List_FrameDropDown_Initialize()
if (not SA_OPTIONS) then
-- options not available yet (onload event) -> abort
return;
end
item = {};
item.text = "Filter targets";
if (SA_OPTIONS.Filter) then
item.checked = 1;
end
item.func = SA_List_Menu_Filter;
UIDropDownMenu_AddButton(item);
item = {};
item.text = "Assist with pet";
if (SA_OPTIONS.AutoPetAttack) then
item.checked = 1;
end
item.keepShownOnClick = 1;
item.func = SA_List_Menu_AssistWithPet;
UIDropDownMenu_AddButton(item);
item = {};
item.text = "Assist only players nearby (28 yards)";
if (SA_OPTIONS.AssistOnlyNearest) then
item.checked = 1;
end
item.func = SA_List_Menu_AssistOnlyNearest;
UIDropDownMenu_AddButton(item);
item = {};
item.text = "Display out of combat targets";
item.checked = SA_OPTIONS.OutOfCombat;
item.func = SA_List_Menu_ShowOOC;
UIDropDownMenu_AddButton(item);
item = {};
item.text = "Lock list position";
item.func = SA_List_Menu_Lock;
item.checked = SA_OPTIONS.LockList;
UIDropDownMenu_AddButton(item);
item = {};
item.text = "SmartAssist options";
item.notCheckable = 1;
item.func = SA_ShowOptions;
UIDropDownMenu_AddButton(item);
end
function SA_List_Menu_Lock()
SA_ToggleOption("LockList");
end
function SA_List_Menu_AssistWithPet()
SA_ToggleOption("AutoPetAttack");
end
function SA_List_Menu_AssistOnlyNearest()
SA_ToggleOption("AssistOnlyNearest");
if (SA_OPTIONS.AssistOnlyNearest) then
printInfo("Assisting only players nearby");
end
end
function SA_List_Menu_ShowOOC()
SA_ToggleOption("OutOfCombat");
end
function SA_List_Menu_Filter()
if (SA_OPTIONS.Filter == nil) then
SAFilterFrame:Show();
else
SA_OPTIONS.Filter = nil;
printInfo("Filtering disabled");
SA_List_SetTitleButton(MODE_OOC);
end;
end
function SA_List_FilterButtonOK_OnClick()
local text = SAFilterEditBox:GetText();
if (string.len(text) > 0) then
SA_OPTIONS.Filter = string.lower(text);
printInfo("SmartAssist will now ignore targets which name doesn't contain text '"..text.."' until you disable filtering. Note that filtering applies only assisting, it doesn't include fallback to nearest.");
SA_List_SetTitleButton(MODE_FILTERED);
else
SA_OPTIONS.Filter = nil;
printInfo("Filtering disabled");
SA_List_SetTitleButton(MODE_OOC);
end
SAFilterFrame:Hide();
end
------------------------------------------------------------------------------
-- Title button clicked (show menu) or drag
-- kudos goes for DamageMeters
------------------------------------------------------------------------------
function SA_List_TitleButton_OnClick()
local button = arg1;
if ( button == "LeftButton" and not SA_OPTIONS.LockList) then
-- drag frame
if ( this:GetButtonState() == "PUSHED" ) then
SAListFrame:StopMovingOrSizing();
else
SAListFrame:StartMoving();
end
elseif ( button == "RightButton" ) then
-- show menu
ToggleDropDownMenu(1, nil, SAListFrameDropDown, "SAListFrameDropDown", -33, 25);
end
end
------------------------------------------------------------------------------
-- change outlook for the list depending options
------------------------------------------------------------------------------
function SA_List_HasSideIcons()
if (SA_OPTIONS.ClassIconMode==2 or SA_OPTIONS.ClassIconMode==3 or
SA_OPTIONS.TargetIconMode==2 or SA_OPTIONS.TargetIconMode==3 or
SA_OPTIONS.HuntersMarkIconMode==2 or SA_OPTIONS.HuntersMarkIconMode==3)
then
return true;
end
end
function SA_List_UpdateAppearance()
local width = SA_OPTIONS.ListWidth;
local x = 0;
local y = 0;
if (SA_OPTIONS.ListHorizontal) then
-- horizontal
local gap = 10;
if (SA_List_HasSideIcons()) then
gap = gap - 30;
end
if (SA_OPTIONS.ListSpacing > 0) then
x = width - gap + SA_OPTIONS.ListSpacing;
else
x = - (width - gap - SA_OPTIONS.ListSpacing);
end
else
-- vertical
local height = ceil(Target1:GetHeight()) - 8;
if (SA_OPTIONS.ListSpacing > 0) then
y = height + SA_OPTIONS.ListSpacing;
else
y = - (height-SA_OPTIONS.ListSpacing);
end
end
SAListFrame:SetWidth(width);
SAListTitleButton:SetWidth(width);
local anchor="TOPLEFT";
for i,box in SA_LIST_BOXES do
if (i==1) then
-- first box is ancored to title
if (y<=0) then
box.frame:SetPoint(anchor, "SAListFrame", anchor, 0, -17);
else
box.frame:SetPoint(anchor, "SAListFrame", anchor, 0, 54);
end
elseif (i==6 and SA_OPTIONS.ListTwoRow) then
-- two rows
if (SA_OPTIONS.ListHorizontal) then
local gap = SA_OPTIONS.ListSpacing;
if (gap>0) then
gap = -gap;
end
gap = gap + 10;
box.frame:SetPoint(anchor, "Target1", "BOTTOMLEFT", 0, gap);
else
local gap = SA_OPTIONS.ListSpacing;
if (gap<0) then
gap = -gap;
end
gap = gap - 8;
-- if icons visible next to box
if (SA_List_HasSideIcons()) then
gap = gap + 30;
end
box.frame:ClearAllPoints();
box.frame:SetPoint(anchor, "Target1", "TOPRIGHT", gap, 0);
end
else
-- rest are anchored to previous box
box.frame:ClearAllPoints();
box.frame:SetPoint(anchor, "Target"..i-1, anchor, x, y);
end
box.frame:SetWidth(width);
-- scale inside elements width
box.mobBar:SetWidth(width-20);
box.targetBar:SetWidth(width-20);
box.mobText:SetWidth(width-30);
box.targetText:SetWidth(width-30);
-- update display targeted by stuff
box.targetOf:SetWidth(width-20);
-- set texts alpha
box.mobText:SetAlpha(SA_OPTIONS.TextAlpha);
box.targetText:SetAlpha(SA_OPTIONS.TextAlpha);
-- set icon positions
if (SA_OPTIONS.ClassIconMode>1) then
local icon = SA_ICONPOS[SA_OPTIONS.ClassIconMode];
SA_List_UpdateIconAppearance(box.classIcon, i, icon);
else
box.classIcon:Hide();
end
if (SA_OPTIONS.TargetIconMode>1) then
local icon = SA_ICONPOS[SA_OPTIONS.TargetIconMode];
SA_List_UpdateIconAppearance(box.targetIcon, i, icon);
else
box.targetIcon:Hide();
end
if (SA_OPTIONS.HuntersMarkIconMode>1) then
local icon = SA_ICONPOS[SA_OPTIONS.HuntersMarkIconMode];
SA_List_UpdateIconAppearance(box.huntersMarkIcon, i, icon);
else
box.huntersMarkIcon:Hide();
end
end
end
-- helper function, updates icon appearance
function SA_List_UpdateIconAppearance(frame, i, icon)
frame:ClearAllPoints();
frame:SetPoint(icon.point, "Target"..i, icon.point, icon.x, icon.y);
frame:SetWidth(icon.width);
frame:SetHeight(icon.height);
frame:Show();
end
------------------------------------------------------------------------------
-- Refresh the list if enough time has passed since last refresh
------------------------------------------------------------------------------
function SA_List_OnUpdate(elapsed)
SA_LASTREFRESH = SA_LASTREFRESH - elapsed;
if (SA_LASTREFRESH > 0) then
return;
end
SA_LASTREFRESH = SA_BASERATE + (SA_INCREASE * SA_PREV.mob_count);
SA_List_Update();
end
local TARGET_CLICKED = time()
function SA_List_Target_OnClick(arg)
SA_Debug("TargetClick");
TARGET_CLICKED = time();
local target = arg.obj;
if (not target) then printInfo("SmartAssist: Unknown target?"); return; end;
-- if ctrl+alt is down paste all targetters names (except tanks) to chat
if (IsControlKeyDown() and IsAltKeyDown()) then
local names = "";
local i = 0;
for _,c in target.players do
if (not SA_IsTank(c.unitName)) then
names = names..c.unitName..", ";
i = i + 1;
end;
end
if (i>0) then
names = string.sub(names, 0, -3);
ChatFrameEditBox:SetText(names.." ");
ChatFrameEditBox:Show();
end
return;
end
-- todo: problem is that target.players[1].unitName may have changed target between updating the list --> click
-- however we could impove situation by assisting the player that has the MOST common target amon all targetters
-- ie. iterate all targetters and check if UnitIsUnit(unit, others) the player who has most highest count is
-- most likelly the correct one! That would however do 40*39 (1590) checks at worst!
-- additionally / alternatively we could check target name (if only one player for example) and disaply
-- error (+sound?) if it has been changed
-- initial implementation (just verboses when debug on)
--local counts = {};
local hicount = 0;
local unitId = "";
for _,player in target.players do
--counts[player.unitId] = SA_List_TargetShareCount(player, target.players);
local count = SA_List_TargetShareCount(player, target.players);
if (count > hicount) then
hicount = count;
unitId = player.unitId;
end
end
--for unitId,count in counts do
--SA_Debug(unitId.." shares target with "..tostring(count), 1);
--end
SA_Debug("Assisting "..unitId.." which has highest common count of "..hicount);
AssistUnit(unitId);
-- initiate assist
--SA_Debug("assisting "..target.players[1].unitName);
--AssistUnit(target.players[1].unitId);
SA_PostAssist();
-- update the list immediattely
SA_PREV.title_mode = -1; -- resets title mode on next refresh
SA_List_Refresh();
end
-- return number of players in list that have same target as player
function SA_List_TargetShareCount(player, list)
local count = 0;
for _,compare in list do
if (UnitIsUnit(player.unitId.."target", compare.unitId.."target")) then
count = count + 1;
end
end
return count;
end
function SA_List_Target_OnEnter(arg)
local text = SA_List_Target_GetTooltip(arg);
GameTooltip:SetOwner(arg, "ANCHOR_LEFT");
GameTooltip:SetText(text,1,1,1,1,1);
-- prevent going to pausemode if target has just been clicked
if (time() - TARGET_CLICKED > 3) then
-- Add some "sleep" to refreshing the list. It's not good to update the list while user is trying to select something.
SA_LASTREFRESH = SA_BASERATE * 3;
SA_PREV.title_mode = -1; -- resets title mode on next refresh
SA_List_SetTitleButton(MODE_PAUSED);
end
end
function SA_List_Target_OnLeave(arg)
GameTooltip:Hide();
end
function SA_List_Target_GetTooltip(arg)
local target = arg.obj;
if (not target) then return "Unknown?"; end;
local text = target.fullName.."\nTargetted by:\n";
for k,v in target.players do
-- colorize text by class
local cv = RAID_CLASS_COLORS[string.upper(v.class)];
local color="";
if (not cv) then
color = "|cff888888";
else
color = SA_ToTextCol(cv.r, cv.g, cv.b);
end
text = text .. color..v.unitName .. "|r" .. "\n";
end
return text;
end
------------------------------------------------------------------------------
-- Request list to be refreshed immediattely
------------------------------------------------------------------------------
function SA_List_Refresh()
--SA_Debug("Requesting refresh now, target="..tostring(UnitName("target")));
SA_LASTREFRESH = 0;
end
------------------------------------------------------------------------------
-- get puller from candidate list
------------------------------------------------------------------------------
function SA_GetPuller(candidates)
for _,v in candidates do
if (v.unitName == SA_OPTIONS.puller) then
return v;
end
end
end
------------------------------------------------------------------------------
-- check if candidates target is already targetted by someone
-- return the target if found and nil if not
------------------------------------------------------------------------------
function SA_GetExistingTarget(candidate, targets)
for _,target in targets do
if (UnitIsUnit(target.players[1].target, candidate.target)) then
return target;
end
end
return nil;
end
function SA_List_NameSplit(str)
local t = {n=0}
local function helper(word) table.insert(t, word) end
if not string.find(string.gsub(str, "%w+", helper), "%S") then return t end
end
------------------------------------------------------------------------------
-- construct target from candidate
------------------------------------------------------------------------------
function SA_GetTarget(candidate, pullerId)
target = {};
target["players"] = { candidate };
target["name"] = UnitName(candidate.target);
target["fullName"] = target.name;
-- intelligent name split
if (SA_OPTIONS.IntelligentSplit and target.name) then
local parts = SA_List_NameSplit(target.name);
if (parts) then
if (table.getn(parts)>2) then
if (parts[2]~="of") then -- splitting "shade of naxxramas" -> "of naxxramas" is stupid, dont split if second word is "of"
target.name = string.sub(target.name, string.len(parts[1])+1 );
end
end
end
end
target["health"] = UnitHealth(candidate.target);
target["targetName"] = UnitName(candidate.target.."target");
-- test fix for "shang's problem"
-- this seems to happend when unit is near edge of known area and it's target is outide of it. Hence my client doesn't know anything about this unit ..
if (target.targetName=="Unknown Entity" or target.targetName=="Unknown") then
target.targetName=nil;
end
-- target.self gives us a reference to mob, example: party<n>target
target["self"] = candidate.target;
target["targetHealth"] = ceil( UnitHealth( candidate.target.."target" ) / UnitHealthMax( candidate.target.."target" ) * 100 );
local _,targetClass = UnitClass(target.self);
target["targetClass"] = targetClass;
target["playersCount"] = 1;
if (SA_IsMarked(candidate.target)) then
target["marked"] = true;
else
target["marked"] = false;
end
if (isUnitCC(candidate.target)) then
target["cced"] = true;
else
target["cced"] = false;
end
-- todo: xxx, only if enabled
target["icon"] = GetRaidTargetIndex(target.self);
if (not target.icon) then
target["icon"] = 0;
end
-- is world boss, elite etc
target["classification"] = UnitClassification(candidate.target);
-- set myTarget to true if this is my target
target["myTarget"] = UnitIsUnit(target.self, "target");
if (pullerId~="") then
target["pullerTarget"] = UnitIsUnit(target.self, pullerId.."target");
end
-- is unit in combat, 20.6.2006 - if it has target, treat as in combat!
target["inCombat"] = UnitAffectingCombat(target.self) or target.targetName;
return target;
end
-- return true if this candidate target should be added to list
function SA_Add_To_List(candidate)
if( UnitCanAssist("player", candidate.unitId) and
UnitExists(candidate.target) and
((UnitAffectingCombat(candidate.target) or SA_OPTIONS.OutOfCombat) and not UnitIsDead(candidate.target)) and
UnitCanAttack("player", candidate.target))
then
return true;
else
return false;
end
end
function SA_List_SortTarget(a,b)
-- marked first
if (a.marked and not b.marked) then return true; end;
if (b.marked and not a.marked) then return false; end;
-- puller target second
--if (a.pullerTarget and not b.pullerTarget) then return true; end;
--if (b.pullerTarget and not a.pullerTarget) then return false; end;
-- ooc last
if (a.inCombat and not b.inCombat) then return true; end;
if (b.inCombat and not a.inCombat) then return false; end;
-- cced second lastest
if (a.cced and not b.cced) then return false; end;
if (b.cced and not a.cced) then return true; end;
-- if both unmarked, then sort by name
if (a.name == b.name) then
return a.playersCount > b.playersCount;
else
return a.name > b.name;
end
end
------------------------------------------------------------------------------
-- updates the available assists list
------------------------------------------------------------------------------
-- this table contains all variables used in incoming detection & printing
local incoming = { prev_iter=0, currently=0, prev_time=0 };
function SA_List_Update()
-- if disabled, stop immediattely
if (not SA_OPTIONS.ShowAvailable) then return; end
local candidates, members= SA_GetCandidates(false)
table.sort(candidates, function(a,b) return SA_SortCandidate(a,b,members) end);
-- filter out candidates out of range if assisting only members nearby
-- TODO: might not be good since causes overheading AND we should still add those players outside range to target?
if (SA_OPTIONS.AssistOnlyNearest) then
candidates = SA_FilterCandidatesByDistance(candidates, false);
end
-- add player to candidates if enabled
if (UnitExists("target") and SA_OPTIONS.AddMyTarget) then
table.insert(candidates, SA_GetPlayerAsCandidate());
end
local aggro_count = 0;
local wb_count = 0;
local pullerId = "";
if (SA_OPTIONS.puller) then
local puller = SA_GetPuller(candidates);
-- puller might be null if it doesn't exist in group
if (puller) then
pullerId = puller.unitId;
end
end
-- construct list of available assists / targets
local targets = {};
for _,candidate in candidates do
if (SA_Add_To_List(candidate)) then
local target = SA_GetExistingTarget(candidate, targets);
if (target) then
-- append targetting candidate to target
table.insert(target.players, candidate);
target.playersCount = target.playersCount + 1;
else
-- this candidate target is not targetted by anyone else, construct new target to the list
local target = SA_GetTarget(candidate, pullerId);
-- filtering if enabled
if (SA_OPTIONS.Filter) then
if string.find(string.lower(target.fullName), SA_OPTIONS.Filter) then
table.insert(targets, target);
end
else
table.insert(targets, target);
end
end
end
end
-- update non-aggro cache and mark cache, this is used when SORTING candidates (see SA_SortCandidate)
SA_MARKEDCACHE = {};
SA_PASSIVECACHE = {};
local dirty = false;
local i = 0;
local mc = 0;
local ooc_seen = false;
for _,target in targets do
i = i + 1;
if (target.marked) then
if (i ~= 1 and mc == 0) then
-- marked target not in first place, list is tainted
SA_Debug("mark dirty list "..target.name, 1);
dirty = true;
end
mc = mc + 1;
for _,c in target.players do
SA_MARKEDCACHE[c.unitName] = true;
end
end
if (not target.inCombat or target.cced) then
ooc_seen = true;
for _,c in target.players do
SA_PASSIVECACHE[c.unitName] = true;
end
else
-- incombat targets after ooc targets, list is tainted
if (ooc_seen) then
SA_Debug("ooc dirty list "..target.name, 1);
dirty = true;
end
end
end
-- if list is dirty abort refresh and request new one with correct cache,
-- update 22.4.2006 cache is not correct on next refresh either, in fact it may pass long time it is okay.
-- hence added PREV_DIRTY flag until problem is investigated
-- update 20.6.2006 sort does not seem to work correctly with buff (ie. hunters mark) priorization!
-- update 09.7.2006 sorting seems to work fine now, cleanup this + futile flag?
if (dirty and not SA_PREV.dirty) then
-- try again soon
SA_LASTREFRESH = 0.2;
SA_PREV.dirty = true;
return;
end
SA_PREV.dirty = false;
-- sort targets depending options
if (SA_OPTIONS.PreserveOrder) then
table.sort(targets, function(a,b) return SA_List_SortTarget(a,b) end);
end
------------------------------------------------------------------------------
local i = 0;
local overloaded = false;
for _,target in targets do
i = i + 1;
if (i>10) then
overloaded = true;
break;
end
local box = SA_LIST_BOXES[i];
box.frame.obj = target; -- store the target data to box (used ie. in tooltips)
box.frame:Show();
-- set values & texts
local targetText = target.players[1].unitName;
if (not SA_OPTIONS.HideTBY) then
targetText = "|cffffffffT.by |r"..targetText;
end
if (target.playersCount > 1) then
targetText = targetText.." + "..tostring(target.playersCount-1); -- -1 for the one who targets (who + n)
end
-- append prefixes to mob name + for elite, WB+ for worldboss
local mobText = target.name;
if (target.classification == "elite") then
mobText = SA_SEMIALERT.."+|r"..mobText;
end
if (target.classification == "worldboss") then
mobText = SA_SEMIALERT.."WB+|r"..mobText;
if (target.inCombat) then
wb_count = wb_count + 1;
end
end
box.mobBar:SetValue(target.health);
box.mobText:SetText(mobText);
-- colorize box
if (not target.inCombat) then
-- if this is out of combat and my target, apply only slight green efect
if (target.myTarget) then
box.frame:SetBackdropColor(0,0.65,0,0.65);
box.frame:SetBackdropBorderColor(0,1,0,0.75);
elseif (target.pullerTarget) then
-- yellow background on puller target
box.frame:SetBackdropColor(1,1,0,0.3);
box.frame:SetBackdropBorderColor(0,0,0,0.4); -- regular grey
else
box.frame:SetBackdropColor(0,0,0,0.4);
box.frame:SetBackdropBorderColor(0,0,0,0.4); -- regular grey
end
else
local addinc = true;
-- set border color
if (target.marked) then
box.frame:SetBackdropBorderColor(1,0,0,1);
elseif (target.myTarget) then
box.frame:SetBackdropBorderColor(0,1,0,1);
elseif (target.cced) then
box.frame:SetBackdropBorderColor(0,0,0,1);
addinc = false;
else
box.frame:SetBackdropBorderColor(0.8,0.8,0.8,1);
end
-- add to incoming
if (addinc) then
incoming.currently = incoming.currently + 1;
end
-- set background color
if (target.myTarget) then
box.frame:SetBackdropColor(0,0.75,0,0.85);
elseif (target.pullerTarget) then
-- yellow background on puller target
box.frame:SetBackdropColor(1,1,0,0.3);
else
box.frame:SetBackdropColor(0,0,0,0.5);
end
end
-- colorize target target text in some situations
if (target.targetName) then
local col = "";
local endcol = "";
if (UnitName("player") == target.targetName) then
-- targetting player
aggro_count = aggro_count + 1;
if (SA_OPTIONS.TankMode) then
col = SA_SEMIALERT;
else
col = SA_ALERTCOL;
end
elseif (not SA_IsTank(target.targetName) and SA_OPTIONS.TankMode) then
-- targeting non tank in tank mode
col = SA_ALERTCOL;
elseif (SA_IsTank(target.targetName)) then
-- targeting tank always on tank color, regardless of tank mode
col = SA_TANKCOL;
end
-- append end of color code marking
if (col~="") then
endcol = "|r";
end
box.targetBar:SetValue(target.targetHealth);
box.targetText:SetText("T:"..col..target.targetName..endcol);
else
box.targetBar:SetValue(0);
box.targetText:SetText("?");
end
-- colorize mob bar
if (UnitIsTapped(target.self) and not UnitIsTappedByPlayer(target.self)) then
-- target is "grey" to us
box.mobBar:SetStatusBarColor(0.8, 0.8, 0.8);
elseif (UnitPlayerControlled(target.self)) then
-- pvp target
box.mobBar:SetStatusBarColor(1, 0, 0);
elseif (not target.inCombat) then
-- out of combat target
box.mobBar:SetStatusBarColor(0.38, 0.38, 0.38);
else
-- normal green
box.mobBar:SetStatusBarColor(0, 1, 0);
end
-- make texts visible always (bugs on some systems)
-- code peeked from TextStatusBar_UpdateTextString sources
-- perhaps I should've called that method but it does some other unwanted things
box.mobBar.TextString:Show();
box.targetBar.TextString:Show();
box.targetOf:SetText(targetText);
-- set class icon (texture coordinates)
local coords = SA_TEXTCOORDS[target.targetClass];
box.classIcon:SetTexCoord(coords.left, coords.right, coords.top, coords.bottom);
-- set target icon (texture coordinates)
-- TODO: xxx, only if feature enabled
if (target.icon>0) then
local icon = UnitPopupButtons["RAID_TARGET_"..target.icon];
box.targetIcon:SetTexCoord(icon.tCoordLeft, icon.tCoordRight, icon.tCoordTop, icon.tCoordBottom );
box.targetIcon:Show();
else
box.targetIcon:Hide();
end
-- hunters mark icon
if (target.marked and SA_OPTIONS.HuntersMarkIconMode>1) then
box.huntersMarkIcon:Show();
else
box.huntersMarkIcon:Hide();
end
end
------------------------------------------------------------------------------
-- if count has been changed update visibility
-- TODO: apparently there is no performance loss calling hide/show .. so this is partially futile now
if (i ~= SA_PREV.mob_count) then
for j = i + 1, SA_PREV.mob_count do
if (j>10) then
break;
end
SA_LIST_BOXES[j].frame:Hide();
end
end
-- if player have a ACQUIRED aggro, play optional sound to alert player
if (aggro_count > SA_PREV.aggro_count) then
if (SA_OPTIONS.AudioWarning) then PlaySound(SA_OPTIONS.SoundGainAggro); end;
if (SA_OPTIONS.VerboseAcquiredAggro) then
SA_Verbose("Acquired aggro!", COLOR_ALERT);
end
end
-- if player have a LOST aggro, play optional sound to alert player
if (aggro_count < SA_PREV.aggro_count and i >= SA_PREV.mob_count) then
if (SA_OPTIONS.LostAudioWarning) then PlaySoundFile(SA_OPTIONS.SoundLoseAggro); end;
if (SA_OPTIONS.VerboseLostAggro) then
SA_Verbose("Lost aggro!", COLOR_ALERT);
end
end
-- if incoming worldbosses, play optional sound to alert player, TODO: OPTION!
if (wb_count > SA_PREV.wb_count) then
SA_Verbose("Incoming worldboss!", COLOR_ALERT);
PlaySoundFile(SA_OPTIONS.SoundIncomingWoldBoss);
end
-- if we have new mobs in combat
-- TODO: on incoming worldboss level unit play alert sound!
if (SA_OPTIONS.VerboseIncoming) then
local now = time();
if (incoming.currently > incoming.prev_iter and now - incoming.prev_time > 4) then
local amount = incoming.currently - incoming.prev_iter;
if (amount > 1) then
SA_Verbose("Incoming x"..amount.."!", COLOR_ALERT);
else
SA_Verbose("Incoming!", COLOR_ALERT);
end
incoming.prev_time = now;
end
incoming.prev_iter = incoming.currently;
incoming.currently = 0;
end
-- update title to correct mode
if (i>0) then
title_mode = MODE_NORMAL;
else
title_mode = MODE_OOC;
end
if (SA_OPTIONS.Filter) then
title_mode = MODE_FILTERED;
end
if (SA_OPTIONS.AssistOnlyNearest) then
title_mode = MODE_NEAREST;
end
if (overloaded) then
title_mode = MODE_OVERLOADED;
end
-- update title button if mode has been changed
if (title_mode ~= SA_PREV.title_mode) then
SA_List_SetTitleButton(title_mode);
end
-- set prev data for next iteration
SA_PREV.title_mode = title_mode;
SA_PREV.mob_count = i;
SA_PREV.wb_count = wb_count;
SA_PREV.aggro_count = aggro_count;
end
------------------------------------------------------------------------------
-- Title button handling
------------------------------------------------------------------------------
function SA_List_SetTitleButton(mode)
if (mode == MODE_NORMAL or mode == MODE_OOC) then
if (mode == MODE_NORMAL) then
SAListTitleButton:SetAlpha(1);
else
if (SA_OPTIONS.HideTitle) then
SAListTitleButton:SetAlpha(0);
else
SAListTitleButton:SetAlpha(SA_OPTIONS.ListOOCAlpha);
end
end
SAListTitleButton:SetBackdropColor(0, 0, 0, 0.3);
SAListTitleButton:SetBackdropBorderColor(1,1,1,1)
SAListTitle:SetText("Available assists");
elseif (mode == MODE_FILTERED or mode == MODE_NEAREST) then
SAListTitleButton:SetAlpha(1);
SAListTitleButton:SetBackdropColor(0,0.6,0.8,1);
SAListTitleButton:SetBackdropBorderColor(0,0.6,0.8,1);
local text = "";
if (mode == MODE_FILTERED) then
text = "Filtered";
end
if (mode == MODE_NEAREST) then
text = "Nearest";
end
SAListTitle:SetText(text);
elseif (mode == MODE_PAUSED) then
SAListTitleButton:SetAlpha(1);
SAListTitleButton:SetBackdropColor(0.3,0.3,0.3,1);
SAListTitleButton:SetBackdropBorderColor(0.6,0.6,0.6,1);
SAListTitle:SetText("Paused");
elseif (mode == MODE_OVERLOADED) then
SAListTitleButton:SetAlpha(1);
SAListTitleButton:SetBackdropColor(1,0,0,1);
SAListTitleButton:SetBackdropBorderColor(1,0,0,1);
SAListTitle:SetText("OVERLOADED");
else
printInfo("smartassist error: unknown title mode "..tostring(mode));
end
end
SA_PREV_ALPHA = 1;
function SA_List_TitleButton_OnEnter()
SA_PREV_ALPHA = SAListTitleButton:GetAlpha();
SAListTitleButton:SetAlpha(1);
end
function SA_List_TitleButton_OnLeave()
SAListTitleButton:SetAlpha(SA_PREV_ALPHA);
end
Generated by GNU Enscript 1.6.5.90.