WoWInterface SVN PowerAurasClassic

[/] [trunk/] [PowerAuras/] [PowerAurasClasses.lua] - Rev 24

Compare with Previous | Blame | View Log

-- PowaAura Classes
-- class.lua
-- Compatible with Lua 5.1 (not 5.0).
function PowaClass(base,ctor)
        local c = {}     -- a new class instance
        if not ctor and type(base) == 'function' then
      ctor = base;
      base = nil;
        elseif type(base) == 'table' then
   -- our new class is a shallow copy of the base class!
      for i,v in pairs(base) do
          c[i] = v;
      end
          if (type(ctor)=="table") then
                for i,v in pairs(ctor) do
                        c[i] = v;
                end
                ctor = nil;
          end
      c._base = base;
        end
        -- the class will be the metatable for all its objects,
        -- and they will look up their methods in it.
        c.__index = c

        -- expose a ctor which can be called by <classname>(<args>)
        local mt = {}
        mt.__call = function(class_tbl,...)
                local obj = {}
                setmetatable(obj,c)
                if ctor then
                        --PowaAuras:Message("Call constructor "..tostring(ctor));
                        ctor(obj,...)
                end 
                return obj
        end
    
    if ctor then
                c.init = ctor;
    else 
                if base and base.init then
                        c.init = base.init;
                        ctor = base.init;
                end
    end
 
        c.is_a = function(self,klass)
      local m = getmetatable(self)
      while m do 
         if m == klass then return true end
         m = m._base
      end
      return false
    end
  setmetatable(c,mt)
  return c
end

cPowaStacks = PowaClass(function(stacker, id, base)
        stacker.enabled = false;
        stacker.x = 0;
        stacker.y = 0;
        stacker.a = 1.0;
        stacker.h = 1.0;
        stacker.Transparent = false;
        stacker.HideLeadingZeros = false;
        --PowaAuras:Message("cPowaTimer");
        if (base) then
                for k, v in pairs (stacker) do
                        --PowaAuras:Message("  base."..tostring(k).."="..tostring(base[k]));
                        local varType = type(v);
                        if (varType == "string" or varType == "boolean" or varType == "number") then
                                if (base[k] ~= nil) then
                                        stacker[k] = base[k];
                                end
                        end
                end
        end
        stacker.Showing = false;
        stacker.id = id;
end);
function cPowaStacks:Update()
        PowaAuras:UnitTestInfo("Stacks.Update ",self.id);
        local aura = PowaAuras.Auras[self.id];
        if (aura == nil) then
                PowaAuras:UnitTestInfo("Stacks aura missing");
                return;
        end
        if (self.enabled==false) then 
                PowaAuras:UnitTestInfo("Stacks disabled");
                return;
        end
        local newvalue = 0;
        if (PowaAuras.ModTest) then
                newvalue = random(1,12);
        else
                newvalue = aura.StackCount;
        end
        if (not newvalue or newvalue==0) then
                local frame = PowaAuras.StacksFrames[self.id];
                if (frame and frame:IsVisible()) then
                        frame:Hide();
                end
                self.Showing = false;
                return;
        end
        PowaAuras:CreateStacksFrameIfMissing(self.id);
        self:ShowValue(aura, newvalue);
        self.Showing = true;
        self.HideRequest = false;
end


function cPowaStacks:ShowValue(aura, newvalue)
        local frame = PowaAuras.StacksFrames[self.id];
        if (aura.texmode == 1) then
                frame.texture:SetBlendMode("ADD");
        else
                frame.texture:SetBlendMode("DISABLE");
        end
        local auraTexture = PowaAuras.Textures[self.id];
        if (auraTexture) then
                if auraTexture:GetObjectType() == "Texture" then
                        frame.texture:SetVertexColor(auraTexture:GetVertexColor());
                elseif auraTexture:GetObjectType() == "FontString" then
                        frame.texture:SetVertexColor(auraTexture:GetTextColor());
                end
        else
                timerFrame.texture:SetVertexColor(aura.r,aura.g,aura.b);
        end

        --PowaAuras:Message("newvalue=", newvalue);
        
        local deci = math.floor(newvalue / 10);
        local uni  = math.floor(newvalue - (deci*10));
        --PowaAuras:Message("Show stacks: ",deci, " ", uni);
        local tStep = PowaAuras.Tstep;
        if (deci==0) then
                frame.texture:SetTexCoord(tStep , tStep * 1.5, tStep * uni, tStep * (uni+1));
        else
                frame.texture:SetTexCoord(tStep * uni, tStep * (uni+1), tStep * deci, tStep * (deci+1));
        end
        if (not frame:IsVisible()) then
                --PowaAuras:Message("Show Stacks Frame for ", self.id);
                frame:Show(); 
        end
end

function cPowaStacks:Hide()
        --PowaAuras:Message("Hide Stacks Frame for ", self.id, " ", self.Showing, " ", PowaAuras.StacksFrames[self.id]);
        if (not self.Showing) then return; end
        if (PowaAuras.StacksFrames[self.id]) then
                PowaAuras.StacksFrames[self.id]:Hide();
        end
        self.Showing = false;
        self.HideRequest = true;
end

function cPowaStacks:Delete()
        self:Hide();
        if PowaAuras.StacksFrames[self.id] then
                PowaAuras.StacksFrames[self.id] = nil;
        end
end

------- Timer -------

cPowaTimer = PowaClass(function(timer, id, base)
        timer.enabled = false;
        timer.x = 0;
        timer.y = 0;
        timer.a = 1.0;
        timer.h = 1.0;
        timer.cents = true;
        timer.dual = false;
        timer.Transparent = false;
        timer.HideLeadingZeros = false;
        --PowaAuras:Message("cPowaTimer");
        if (base) then
                for k, v in pairs (timer) do
                        --PowaAuras:Message("  base."..tostring(k).."="..tostring(base[k]));
                        local varType = type(v);
                        if (varType == "string" or varType == "boolean" or varType == "number") then
                                if (base[k] ~= nil) then
                                        timer[k] = base[k];
                                end
                        end
                end
        end
        timer.Showing = false;
        timer.id = id;
        --for k,v in pairs (timer) do
        --      PowaAuras:Message("  "..tostring(k).."="..tostring(v));
        --end
end);


--- ------------------------------------------------------------------------------------------------- TIMERS
function cPowaTimer:Update(elapsed)
        PowaAuras:UnitTestInfo("Timer.Update ",self.id);
        --PowaAuras:Message("Timer.Update ",self.id);
        local aura = PowaAuras.Auras[self.id];
        if (aura == nil) then
                PowaAuras:UnitTestInfo("Timer aura missing");
                --PowaAuras:Message("Timer aura missing");
                return;
        end
        if (self.enabled==false) then
                PowaAuras:UnitTestInfo("Timer disabled");
                --PowaAuras:Message("Timer disabled");
                return;
        end
        
        --PowaAuras:Message("Showing=", aura.Showing);
        --PowaAuras:Message("CanHaveTimer=", aura.CanHaveTimer);
        --PowaAuras:Message("CanHaveTimerOnInverse=", aura.CanHaveTimerOnInverse);
        --PowaAuras:Message("Inverse=", aura.inverse);
        --PowaAuras:Message("CooldownAura=", aura.CooldownAura);
        local auraShowing = aura.Showing and not aura.HideRequest;
        if (not PowaAuras.ModTest and ((not auraShowing and not aura.CooldownAura) or (auraShowing and aura.CooldownAura))) then
                return;
        end

        local debugCycle;
        if (PowaAuras.NextDebugCheck>0 and PowaAuras.DebugTimer > PowaAuras.NextDebugCheck) then
                PowaAuras.DebugTimer = 0;
                --PowaAuras:Message("Update Timer #",self.id); --OK
                debugCycle = true;
        end

        local newvalue;
        --- Determine the value to display in the timer
        if (PowaAuras.ModTest) then
                newvalue = random(0,99) + (random(0, 99) / 100);
        
        elseif (aura.timerduration > 0) then--- if a user defined timer is active for the aura override the rest
                if (aura.target or aura.targetfriend) and (PowaAuras.ResetTargetTimers == true) then
                        self.CustomDuration = aura.timerduration;
                else
                        self.CustomDuration = math.max(self.CustomDuration - elapsed, 0);
                end     
                newvalue = self.CustomDuration;
        else
                newvalue = aura:GetDuration(self.DurationInfo);
        end

        if (debugCycle) then
                PowaAuras:Message("newvalue=",newvalue); --OK
        end

        PowaAuras:UnitTestInfo("Timer newvalue", newvalue);
        --PowaAuras:Message("Timer newvalue=", newvalue);

        if (newvalue and newvalue > 0) then --- Time has value to display

                PowaAuras:CreateTimerFrameIfMissing(self.id);
        
                local large = newvalue;
                if (newvalue > 60.00) then 
                        large = newvalue / 60;          
                end
                large = math.min (99.00, large);

                if (debugCycle) then
                        PowaAuras:Message("large=",large); --OK
                end
                self:ShowValue(aura, 1, large);

                if (debugCycle) then
                        PowaAuras:Message("cents=",self.cents); --OK
                end
                if (self.cents) then
                        local small;
                        if (newvalue > 60.00) then 
                                small = math.fmod(newvalue,60); 
                        else
                                small = (newvalue - math.floor(newvalue)) * 100;
                        end

                        if (debugCycle) then
                                PowaAuras:Message("small=",small); --OK
                        end
                        self:ShowValue(aura, 2, small);
                end     
                self.Showing = true;            
                if (self.HideRequest) then
                        self.HideRequest = false;
                end

        elseif (self.Showing) then
                if (debugCycle) then
                        PowaAuras:Message("HideTimerFrames"); --OK
                end
                --PowaAuras:Message("HideTimerFrames");
                self:Hide();
                PowaAuras:TestThisEffect(self.id);
        end                     
        
end

function cPowaTimer:ShowValue(aura, frameIndex, newvalue)
        local timerFrame = PowaAuras.TimerFrame[self.id][frameIndex];
        if (aura.texmode == 1) then
                timerFrame.texture:SetBlendMode("ADD");
        else
                timerFrame.texture:SetBlendMode("DISABLE");
        end
        local auraTexture = PowaAuras.Textures[self.id];
        if (auraTexture) then
                if auraTexture:GetObjectType() == "Texture" then
                        timerFrame.texture:SetVertexColor(auraTexture:GetVertexColor());
                elseif auraTexture:GetObjectType() == "FontString" then
                        timerFrame.texture:SetVertexColor(auraTexture:GetTextColor());
                end
        else
                timerFrame.texture:SetVertexColor(aura.r,aura.g,aura.b);
        end
        
        --PowaAuras:Message("newvalue=", newvalue);
        
        local deci = math.floor(newvalue / 10);
        local uni  = math.floor(newvalue - (deci*10));
        --PowaAuras:Message("Show timer: ",deci, " ", uni, " ", PowaAuras.Auras[k].Timer.HideLeadingZeros);
        local tStep = PowaAuras.Tstep;
        if (deci==0 and self.HideLeadingZeros) then
                timerFrame.texture:SetTexCoord(tStep , tStep * 1.5, tStep * uni, tStep * (uni+1));
        else
                timerFrame.texture:SetTexCoord(tStep * uni, tStep * (uni+1), tStep * deci, tStep * (deci+1));
        end
        if (not timerFrame:IsVisible()) then
                --PowaAuras:Message("Show timer frame");
                timerFrame:Show(); -- Timer Frame
        end
        --PowaAuras:Message("Show #3 ", k, " ", i, " ", j, " ", seconds);
        
        --PowaAuras:Message("deci=", deci, " uni=", uni);
end


function cPowaTimer:HideFrame(i)
        if (PowaAuras.TimerFrame[self.id] and PowaAuras.TimerFrame[self.id][i]) then
                --PowaAuras:Message("Hide Timer Frame ", i," for ", self.id);
                PowaAuras.TimerFrame[self.id][i]:Hide();
        end
end

function cPowaTimer:Hide()
        if (not self.Showing) then return; end
        if PowaAuras.TimerFrame[self.id] then
                self:HideFrame(1);
                self:HideFrame(2);
        end
        self.Showing = false;
        self.HideRequest = true;
        --PowaAuras:Message("Hide timer frame");
end

function cPowaTimer:Delete()
        self:Hide();
        if PowaAuras.TimerFrame[self.id] then
                PowaAuras.TimerFrame[self.id][1] = nil;
                PowaAuras.TimerFrame[self.id][2] = nil;
                PowaAuras.TimerFrame[self.id] = nil;
        end
end

------------cPowaAura----------------
--   cPowaAura is the base class and is not instanced directly, the other classes inherit properties and methods from it
--===========================

cPowaAura = PowaClass(function(aura, id, base)
        --PowaAuras:Message("cPowaAura constructor " .. tostring(id));
        aura.off = false;
        
        aura.bufftype = PowaAuras.BuffTypes.Buff;
        aura.buffname = "";
        
        aura.texmode = 1;
        aura.wowtex = false;
        aura.customtex = false;
        aura.textaura = false;
        aura.owntex = false;
        aura.realaura = 1;
        aura.texture = 1;
        aura.customname = "";
        aura.aurastext = "";
        aura.aurastextfont = 1;
        aura.icon = "";

        aura.timerduration = 0;
        
        -- Sound Settings
        aura.sound = 0;
        aura.soundfile = "";
        aura.customsound = "";  
        
        -- Animation Settings
        aura.begin = 0;
        aura.anim1 = 1;
        aura.anim2 = 0;
        aura.speed = 1.00;
        aura.finish = 1;
        aura.duration = 0;
        aura.isSecondary = false;
        
        -- Appearance Settings
        aura.alpha = 0.75;
        aura.size = 0.75;
        aura.torsion = 1;
        aura.symetrie = 0;
        aura.x = 0;
        aura.y = -30;
        aura.randomcolor = false;
        aura.r = 1.0;
        aura.g = 1.0;
        aura.b = 1.0;
        
        aura.inverse = false;
        aura.ignoremaj = true;
        aura.exact = false;

        aura.stacks = 0;
        aura.stacksLower = 0;
        aura.stacksOperator = PowaAuras.DefaultOperator;

        aura.threshold = 50;
        aura.thresholdinvert = false;

        aura.mine = false;

        aura.focus = false;
        aura.target = false;
        aura.targetfriend = false;
        aura.raid = false;
        aura.groupOrSelf = false;
        aura.party = false;

        aura.groupany = true;
        aura.optunitn = false;
        aura.unitn = "";

        aura.isinraid = false;
        aura.ismounted = false;
        aura.ignoreResting = true;
        aura.inVehicle = false;
        
        aura.combat = 0;
        aura.spec1 = true;
        aura.spec2 = true;
        aura.gcd = false;
        aura.stance = 10;
        aura.multiids = "";
        aura.tooltipCheck = "";
        
        if (base) then
                for k, v in pairs (aura) do
                        local varType = type(v);
                        if (varType == "string" or varType == "boolean" or varType == "number") then
                                if (base[k] ~= nil) then
                                        aura[k] = base[k];
                                end
                        end
                end
                
                if (base.Timer) then
                --if ((base.CanHaveTimerOnInverse or base.CanHaveTimer) and base.Timer) then
                        aura.Timer = cPowaTimer(id, base.Timer);
                end                             
                
                if (base.Stacks and not base.isSecondary) then
                        aura.Stacks = cPowaStacks(id, base.Stacks);
                end                             
        end
        
        if (not aura.Timer) then
        --if ((base.CanHaveTimerOnInverse or base.CanHaveTimer) and not aura.Timer) then
                aura.Timer = cPowaTimer(id);
        end
        
        if (base.CanHaveStacks and not aura.Stacks and not aura.isSecondary) then
                aura.Stacks = cPowaStacks(id);
        end
        
        if (aura.Timer) then
                aura.Timer.Showing = false;
                aura.Timer.HideRequest = false;
        end
        if (aura.Stacks) then
                aura.Stacks.Showing = false;
                aura.Stacks.HideRequest = false;
        end
        aura.Showing = false;
        aura.HideRequest = false;
        aura.id = id;

end);


function cPowaAura:TimerShowing()
        if (not self.Timer) then return false; end
        return self.Timer.Showing;
end

function cPowaAura:StacksShowing()
        if (not self.Stacks) then return false; end
        return self.Stacks.Showing;
end

function cPowaAura:HideShowTabs()
        if ((self.CanHaveTimer and not self.inverse) or (self.CanHaveTimerOnInverse and self.inverse)) then 
                PowaEditorTab3:Show();
                if (not self.Timer) then
                        self.Timer = cPowaTimer(self.id);
                end
        else
                PowaEditorTab3:Hide();
                if (self.Timer) then
                        self.Timer.enabled = false;
                end
        end
        if (self.CanHaveStacks and not self.inverse) then 
                PowaEditorTab5:Show();
                if (not self.Stacks) then
                        self.Stacks = cPowaStacks(self.id);
                end
        else
                PowaEditorTab5:Hide();
                if (self.Stacks) then
                        self.Stacks.enabled = false;
                end
        end
end
function cPowaAura:GetDuration(durationInfo)
        --PowaAuras:Message("GetDuration=", durationInfo);
        if (durationInfo and durationInfo > 0) then
                return math.max(durationInfo - GetTime(), 0);
        end
        return 0;
end

function cPowaAura:CreateFrames()
        local frame = self:GetFrame();
        if (frame==nil) then
                PowaAuras:UnitTestInfo("New Frames", self.id);
                PowaAuras:UnitTestDebug("Creating frame for aura ", self.id);
                --- Frame --- 
                frame = CreateFrame("Frame","Frame"..self.id, UIParent);
                self:SetFrame(frame);
                
                frame:SetFrameStrata("LOW");
                frame:Hide();  
                
                frame.baseL = 256;
                frame.baseH = 256;
        end
        
        local texture = self:GetTexture();
        if (texture==nil) then
                PowaAuras:UnitTestInfo("New Texture", self.id);
                if self.textaura then
                        PowaAuras:UnitTestDebug("Creating new textstring texture for aura ", self.id);
                        texture = frame:CreateFontString(nil, "OVERLAY");
                        texture:ClearAllPoints();
                        texture:SetPoint("CENTER",frame);
                        texture:SetFont(STANDARD_TEXT_FONT, 20);
                        texture:SetTextColor(self.r,self.g,self.b);
                        texture:SetJustifyH("CENTER");
                else
                        texture = frame:CreateTexture(nil,"BACKGROUND");
                        texture:SetBlendMode("ADD");
                        texture:SetAllPoints(frame); --- attache la texture a la frame
                        frame.texture = texture;
                end
                self:SetTexture(texture);
        else
                if self.textaura then
                        PowaAuras:UnitTestDebug("textaura ", texture:GetObjectType());
                        if texture:GetObjectType() == "Texture" then
                                PowaAuras:UnitTestInfo("Converting to textstring texture for aura ", self.id);
                                PowaAuras:UnitTestDebug("Converting to textstring texture for aura ", self.id);
                                texture:SetTexture(nil);
                                texture = frame:CreateFontString(nil, "OVERLAY");
                                texture:ClearAllPoints();
                                texture:SetPoint("CENTER",frame);
                                texture:SetFont(STANDARD_TEXT_FONT, 20);
                                texture:SetTextColor(self.r,self.g,self.b);
                                texture:SetJustifyH("CENTER");
                                self:SetTexture(texture);
                        end
                else
                        if texture:GetObjectType() == "FontString" then
                                PowaAuras:UnitTestInfo("Converting from textstring texture for aura ", self.id);
                                texture:SetText("");
                                texture = frame:CreateTexture(nil,"BACKGROUND");
                                texture:SetBlendMode("ADD");    
                                texture:SetAllPoints(frame); --- attache la texture a la frame
                                frame.texture = texture;
                                self:SetTexture(texture);
                        end
                end
        end     
        return frame, texture;
end


function cPowaAura:Hide()
        
        PowaAuras:UnitTestInfo("Aura.Hide ", self.id);

        local frame = self:GetFrame();
        if (frame) then
                frame:Hide();
        end
        
        if (not self.isSecondary) then
                if (self.Timer and PowaAuras.ModTest) then self.Timer:Hide(); end
                if (self.Stacks) then self.Stacks:Hide(); end
                local frame = PowaAuras.Frames[self.id];
                if (frame) then
                        frame:Hide();
                end
                local secondaryAura = PowaAuras.SecondaryAuras[self.id];
                if (secondaryAura) then
                        secondaryAura:Hide();
                end
        end

        self.Showing = false;
end

function cPowaAura:AddEffect(i)
        table.insert(PowaAuras.AurasByType[self.AuraType], i);
end

function cPowaAura:IsPlayerAura()
        return  (not self.target) 
                and (not self.targetfriend)
                and (not self.party)
                and (not self.raid) 
                and (not (self.groupOrSelf and (GetNumPartyMembers()>0 or GetNumRaidMembers()>0))) 
                and (not self.focus)
                and (not self.optunitn);
end

function cPowaAura:CheckState(giveReason)
        
        --- player aura but player is dead
        if (self:IsPlayerAura() and self.WeAreAlive == false) then
                if (not giveReason) then return false; end
                return false, "Player is DEAD";
        end
        
        --- n'affiche pas si la cible est inexistante ou morte
        if ((self.target or self.targetfriend) and (UnitName("target") == nil or UnitIsDead("target") or UnitName("target") == UnitName("player")) ) then
                if (not giveReason) then return false; end
                if (UnitName("target") == nil) then
                        return false, "no Target";
                end
                if (UnitName("target") == UnitName("player")) then
                        return false, "Target is you";
                end             
                return false, "Target DEAD";
        end
                        
        --- regarde si la cible est ennemie
        if (self.target and self.targetfriend == false and UnitIsFriend("player","target")) then --- cible amie alors que faut pas
                if (not giveReason) then return false; end
                return false, "Target is fiendly";
        end
                
        --- party
        if (self.party and not ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0))) then --- partycheck yes, but not in party
                if (not giveReason) then return false; end
                return false, "Not in Party";
        end
        
    --- focus
        if (self.focus and (UnitName("focus") == nil or UnitIsDead("focus") or UnitName("focus") == UnitName("player"))) then --- focuscheck
                if (not giveReason) then return false; end
                return false, "No focus";
        end
        
    --- unit
        if (self.optunitn and not ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0) or UnitExists("pet"))) then --- Unitn yes, but not in party/raid or with pet
                if (not giveReason) then return false; end
                return false, "Can't find custom unit not in party, raid or with pet unit="..tostring(self.unitn);
        end
        
    --- raid
        if (self.raid and numrm == 0) then --- raidcheck yes, but not in raid
                if (not giveReason) then return false; end
                return false, "Not in raid";
        end
                
        --- regarde si la cible est amie
        if (self.target == false and self.targetfriend and not UnitIsFriend("player","target")) then --- cible ennemie
                if (not giveReason) then return false; end
                return false, "Target not friend";
        end

        --- dual spec check
        if ((not self.spec2 and PowaAuras.ActiveTalentGroup == 2) or (not self.spec1 and PowaAuras.ActiveTalentGroup == 1)) then
                if (not giveReason) then return false; end
                return false, "Aura not active for this talent spec";
    end
        
        --- mode combat, cache si besoin
        if ((PowaAuras.WeAreInCombat == true and self.combat == 2) or (PowaAuras.WeAreInCombat == false and self.combat == 1)) then
                if (not giveReason) then return false; end
                return false, "Not in combat";
        end
                
        if (PowaAuras.WeAreInRaid == false and self.isinraid == true) then
                if (not giveReason) then return false; end
                return false, "Not in raid";
        end
                
        if (PowaAuras.WeAreMounted ~= self.ismounted) then
                if (not giveReason) then return false; end
                if (PowaAuras.WeAreMounted) then
                        return false, "Mounted";
                else
                        return false, "Not Mounted";
                end
        end     
                
        if (PowaAuras.WeAreInVehicle ~= self.inVehicle) then    
                if (not giveReason) then return false; end
                return false, "Not In Vehicle";
        end     
        
        -- It's not dead it's restin'
        if (self.ignoreResting and (IsResting()==1) and (not PowaAuras.WeAreInCombat)) then     
                if (not giveReason) then return false; end
                return false, "Resting";
        end     
        
        if (not giveReason) then return true; end
        return true, "State OK";
end

function cPowaAura:ShouldShow(giveReason, reverse)
        PowaAuras:UnitTestInfo("ShouldShow", self.id);
        local result, reason = self:CheckState(giveReason);
        if (result) then
                result, reason = self:CheckIfShouldShow(giveReason);
                if (result~=nil and (self.inverse or reverse) and not (self.inverse and reverse)) then
                        result = not result;
                        if (giveReason) then
                                reason = reason .." (inverted)";
                        end
                end
        end
        if (result) then
                PowaAuras:Debug("Aura Should Show ", self.id, " because ", reason);
        else
                PowaAuras:Debug("Aura won't Show ", self.id, " because ", reason);
        end
        return result, reason;
end

function cPowaAura:Display()
        PowaAuras:Message("Aura Display id=", self.id); --OK
        for k,v in pairs (self) do
                PowaAuras:Message("  "..tostring(k).." = "..tostring(v)); --OK
        end
end

function cPowaAura:GetFrame()
        if (self.isSecondary) then
                return PowaAuras.SecondaryFrames[self.id];
        end
        return PowaAuras.Frames[self.id];
end

function cPowaAura:GetTexture()
        if (self.isSecondary) then
                return PowaAuras.SecondaryTextures[self.id];
        end
        return PowaAuras.Textures[self.id];
end

function cPowaAura:SetFrame(frame)
        if (self.isSecondary) then
                PowaAuras.SecondaryFrames[self.id] = frame;
                return;
        end
        PowaAuras.Frames[self.id] = frame;
end

function cPowaAura:SetTexture(texture)
        if (self.isSecondary) then
                PowaAuras.SecondaryTextures[self.id] = texture;
                return;
        end
        PowaAuras.Textures[self.id] = texture;
end

function cPowaAura:GetSpellNameFromMatch(spellMatch)
        local _, _,spellId = string.find(spellMatch, "%[(%d+)%]")
        if (spellId) then               
                local spellName, rank, spellIcon = GetSpellInfo(tonumber(spellId));
                return spellName, spellIcon;
        end
        return spellMatch;
end

function cPowaAura:SetStacks(text)
        local _, _,curStacksLower, curOperator, curStacks = string.find(text, "(%d*)(%D+)(%d*)")

        if (curStacks == nil or curStacks == "") then curStacks = "0"; end
        local stacks = tonumber(curStacks);
        PowaAuras:Debug(stacks);
                
        if (stacks ~= self.stacks) then
                if (stacks > 100) or (stacks < 0) then stacks = 0; end
                self.stacks = stacks or 0;
        end
        
        if (curStacksLower == nil or curStacksLower == "") then curStacksLower = "0"; end
        local stacksLower = tonumber(curStacksLower);
        PowaAuras:Debug(stacksLower);
        
        if (stacksLower ~= self.stacksLower) then
                if (stacksLower > 100) or (stacksLower < 0) or (stacksLower > stacks) then stacksLower = 0; end
                self.stacksLower = stacksLower or 0;
        end
        
        if (curOperator ~= self.stacksOperator) then
                if (not PowaAuras.allowedOperators[curOperator]) then
                        curOperator = PowaAuras.DefaultOperator;
                end     
                self.stacksOperator = curOperator;
        end     
end

function cPowaAura:Trim(s)
    return (string.gsub(s, "^%s*(.-)%s*$", "%1"));
end

function cPowaAura:MatchSpell(spellName, spellTexture, textToFind)
        if (spellName==nil or textToFind==nil) then
                return false;
        end
        if (textToFind=="*") then
                return true;
        end
        PowaAuras:Debug("  MatchSpell spellName   =",spellName);
        PowaAuras:Debug("             spellTexture=",spellTexture);
        PowaAuras:Debug("             textToFind  =",textToFind);
        for pword in string.gmatch(textToFind, "[^/]+") do
                pword = self:Trim(pword);
                if (string.len(pword)>0) then
                        local textToSearch;
                        local textureMatch;
                        if string.find(pword, "_") then
                                 _, _,textToSearch = string.find(spellTexture, "([%w_]*)$")
                        else
                                textToSearch = spellName;
                                pword, textureMatch = self:GetSpellNameFromMatch(pword);
                        end
                        PowaAuras:Debug("textureMatch=", textureMatch);
                        if (not textureMatch or textureMatch==spellTexture) then
                                if (textToSearch) then
                                        if (self.ignoremaj) then
                                                textToSearch = string.upper(textToSearch)
                                                pword = string.upper(pword);
                                        end
                                        PowaAuras:Debug("pword=", pword);
                                        PowaAuras:Debug("search=", textToSearch);
                                        if (self.exact) then
                                                PowaAuras:Debug("exact=", (textToSearch == pword));
                                                if (textToSearch == pword) then
                                                        return true;
                                                end
                                        else
                                                PowaAuras:Debug("find=", string.find(textToSearch, pword, 1, true));
                                                if (string.find(textToSearch, pword, 1, true)) then
                                                        return true;
                                                end
                                        end
                                end
                        end
                end
        end

        return nil;
end

function cPowaAura:MatchText(textToSearch, textToFind)
        if (textToSearch==nil or textToFind==nil) then
                return false;
        end
        if (textToFind=="*") then
                return true;
        end
        PowaAuras:Debug("MatchText textToSearch=",textToSearch," textToFind=",textToFind);
        if (self.ignoremaj) then
                textToFind = string.upper(textToFind);
                textToSearch = string.upper(textToSearch);
        end
        PowaAuras:Debug("MatchText textToSearch=",textToSearch," textToFind=",textToFind, " ignoremaj=", self.ignoremaj, " exact=", self.exact);
        if (self.exact) then
                return (textToSearch == textToFind);
        end
        for pword in string.gmatch(textToFind, "[^/]+") do      
                PowaAuras:Debug("pword=", pword," find=",string.find(textToSearch, pword, 1, true));
                if (string.find(textToSearch, pword, 1, true)) then
                        return true;
                end
        end
        return nil;
end

function cPowaAura:CreateAuraString()
        local tempstr, varpref= "", "";
        for k, v in pairs (self) do
                --- multi condition checks not supported for export.
                if k == "multiids" then
                        v = "";
                end
                local varType = type(v);
                if (varType == "string" or varType == "boolean" or varType == "number") then
                        tempstr = tempstr..k..":"..string.sub(varType,1,2)
                        if (varType == "string") then
                                tempstr = tempstr..v;
                        else
                                tempstr = tempstr..tostring(v);
                        end
                        tempstr = tempstr.."; ";
                end
        end
        if (self.Timer) then
                for k, v in pairs (self.Timer) do
                        local varType = type(v);
                        if (varType == "string" or varType == "boolean" or varType == "number") then
                                tempstr = tempstr.."timer."..k..":"..string.sub(varType,1,2);
                                if (varType == "string") then
                                        tempstr = tempstr..v;
                                else
                                        tempstr = tempstr..tostring(v);
                                end
                                tempstr = tempstr.."; ";
                        end
                end
        end

        if tempstr and tempstr ~= "" then
                tempstr = strtrim(tempstr);
                tempstr = string.sub(tempstr, 1, string.len(tempstr)-1);
        end
        PowaAuras:Debug("Aura-string length: "..tostring(string.len(tempstr)));
        return tempstr;
end

function cPowaAura:GetUnit()
        if (self.target or self.targetfriend) then
                return "target";
        elseif (self.focus) then
                return "focus";
        elseif (self.party) then
                return "party";
        elseif (self.raid) then
                return "raid";
        elseif (self.groupOrSelf) then
                return "groupOrSelf";
        elseif (self.optunitn) then
                return self.unitn;
        else 
                return "player";
        end     
        return nil;
end

function cPowaAura:CheckAllUnits(giveReason)
        local unit = self:GetUnit();            
        PowaAuras:Debug("on unit "..unit);
        local numpm = GetNumPartyMembers();
        local numrm = GetNumRaidMembers();

        if unit == "party" then
                for pm = 1, numpm do
                        unit = "party"..pm;
                        if self:CheckUnit(unit) then
                                if (not giveReason) then return true; end
                                return true, unit.." "..self.MatchReason;
                        end
                end
        elseif unit == "raid" then
                for rm = 1, numrm do
                        unit = "raid"..rm;
                        if self:CheckUnit(unit) then
                                if (not giveReason) then return true; end
                                return true, unit.." "..self.MatchReason;
                        end
                end
        elseif  unit == "groupOrSelf" then
                if (numrm>0) then
                        for rm = 1, numrm do
                                unit = "raid"..rm;
                                if self:CheckUnit(unit) then
                                        if (not giveReason) then return true; end
                                        return true, unit.." "..self.MatchReason;
                                end
                        end
                elseif (numpm>0) then
                        for pm = 1, numpm do
                                unit = "party"..pm;
                                if self:CheckUnit(unit) then
                                        if (not giveReason) then return true; end
                                        return true, unit.." "..self.MatchReason;
                                end
                        end
                        if self:CheckUnit("player") then
                                if (not giveReason) then return true; end
                                return true, unit.." "..self.MatchReason;
                        end
                end
        else
                if self:CheckUnit(unit) then
                        if (not giveReason) then return true; end
                        return true, unit.." "..self.MatchReason;
                end
        end
        if (not giveReason) then return false; end
        return false, unit.." "..self.NoMatchReason;
end

function cPowaAura:CheckStacks(count)
        local operator = self.stacksOperator or PowaAuras.DefaultOperator;
        local stacks = self.stacks or 0;
        local stacksLower = self.stacksLower or 0;
        PowaAuras:Debug("Stack op=",operator," stacks=",stacks,"Stack Count=",count);
        return    ((operator == "="  and stacks == 0)
                        or (operator == ">=" and count >= stacks)
                        or (operator == "<=" and count <= stacks)
                        or (operator == ">"  and count > stacks)
                        or (operator == "<"  and count < stacks)
                        or (operator == "="  and count == stacks)
                        or (operator == "-"  and count >= stacksLower and count <= stacks)
                        or (operator == "!"  and count ~= stacks));
end

cPowaBuffBase = PowaClass(cPowaAura, {CanHaveTimer=true, CanHaveStacks=true});

function cPowaBuffBase:AddEffect(i)

        if not self.target 
   and not self.targetfriend 
   and not self.party
   and not self.raid 
   and not self.groupOrSelf
   and not self.focus
   and not self.optunitn then --- self-buff
                table.insert(PowaAuras.AurasByType.Buffs, i);
        end
        if self.party then --- partybuff cible
                table.insert(PowaAuras.AurasByType.PartyBuffs, i);
        end
        if self.focus then --- focus buffs
                table.insert(PowaAuras.AurasByType.FocusBuffs, i);
        end
        if self.raid then --- raid buffs
                table.insert(PowaAuras.AurasByType.RaidBuffs, i);
        end
        if self.groupOrSelf then --- groupOrSelf buffs
                table.insert(PowaAuras.AurasByType.GroupOrSelfBuffs, i);
        end
        if self.optunitn then --- unit buffs
                table.insert(PowaAuras.AurasByType.UnitBuffs, i);
        end
        if (self.target or self.targetfriend) then --- target buff
                table.insert(PowaAuras.AurasByType.TargetBuffs, i);
        end                     
end

function cPowaBuffBase:IsPresent(unittarget, s)

        PowaAuras:Debug("IsPresent on ",unittarget,"  buffid ",s," type", self.buffAuraType);

        local auraName, _, auraTexture, count, _, _, expirationTime, caster = UnitAura(unittarget, s, self.buffAuraType);
        
        if (auraName == nil) then return nil; end

        PowaAuras:Debug("Aura=",auraName," count=",count," expirationTime=", expirationTime," caster=",caster);

        if (not self:CompareAura(unittarget, s, auraName, auraTexture)) then
                --PowaAuras:Debug("CompareAura not found");
                return false;
        end
        
        local isMine = (caster~=nil) and UnitExists(caster) and UnitIsUnit("player", caster);
        local bemine = self.mine;
        --PowaAuras:Message("Bemine=",bemine," isMine=",isMine);
        if (bemine and isMine) or (not bemine) then
                if (self:CheckStacks(count)) then
                        --PowaAuras:Message("Present!");
                        if (self.Timer) then
                                self.Timer.DurationInfo = expirationTime;
                        end
                        if (self.Stacks) then
                                self.StackCount = count;
                        end                     
                        return true;
                end
        end
        
        return false;
end     

function cPowaBuffBase:CheckTooltip(text, target, index)
        if (text==nil or string.len(text) == 0) then
                return true;
        end

        PowaAuras:Debug("Search in tooltip for ",text);

        PowaAuras_Tooltip:SetOwner(UIParent, "ANCHOR_NONE");
        PowaAuras_Tooltip:SetUnitAura(target, index, self.buffAuraType);
        
        for z = 1, PowaAuras_Tooltip:NumLines() do
                PowaAuras:UnitTestDebug("Check tooltip line ",z);
                local textlinel = getglobal("PowaAuras_TooltipTextLeft"..z);
                local textl = textlinel:GetText();
                local tooltipText = "";
                if textl then
                        tooltipText = tooltipText..textl;
                end
                local textliner = getglobal("PowaAuras_TooltipTextRight"..z);
                local textr = textliner:GetText();
                if textr then
                        tooltipText = tooltipText..textr;
                end
                if (tooltipText ~= "") then
                        PowaAuras:UnitTestDebug("| "..text.." |");              
                        if (string.find(tooltipText, text, 1, true)) then
                                PowaAuras_Tooltip:Hide();
                                return true;
                        end
                end
        end     
        PowaAuras_Tooltip:Hide();
        return false;
end

function cPowaBuffBase:CompareAura(target, z, auraName, auraTexture, giveReason)
        
        --PowaAuras:Debug("CompareAura",z," ",auraName, auraTexture);
        
        if self:MatchSpell(auraName, auraTexture, self.buffname) then
                PowaAuras:UnitTestDebug("Aura match found! ", self.id);
                if (not self:CheckTooltip(self.tooltipCheck, target, z)) then
                        PowaAuras:UnitTestDebug("Tooltip no match found!");
                        if (not giveReason) then return false; end
                        return false, target.." has "..self.auraType.." "..auraName.." but tooltip does not match";
                end
                local tempicon;
                if (self.owntex == true) then
                        getglobal("PowaIconTexture"):SetTexture(auraTexture);
                        tempicon = getglobal("PowaIconTexture"):GetTexture();
                        if (self.icon ~= tempicon) then
                                self.icon = tempicon;
                        end
                end
                if (self.icon == "") then
                        getglobal("PowaIconTexture"):SetTexture(auraTexture);
                        self.icon = getglobal("PowaIconTexture"):GetTexture();
                end
                if (not giveReason) then return true; end
                return true, target.." has "..self.auraType.." "..auraName;     
        end
        if (not giveReason) then return false; end
        return false, target.." does not have "..self.auraType.." "..self.buffname;
end

function cPowaBuffBase:CheckAllAuraSlots(target, giveReason)
        PowaAuras:UnitTestDebug("-------------");
        PowaAuras:UnitTestDebug("CheckAllAuraSlots for ", target);
        for i = 1, 40 do
                local present = self:IsPresent(target, i);
                if (present==nil) then
                        if (not giveReason) then return false; end
                        return false, target.." doesn't have "..self.auraType.." "..self.buffname; 
                end
                if (present) then
                        PowaAuras:UnitTestDebug("CheckAllAuraSlots Present!");
                        if (not giveReason) then return true; end
                        return true, target .." has "..self.auraType.." "..self.buffname;
                end     
        end
        if (not giveReason) then return false; end
        return false, target.." doesn't have "..self.auraType.." "..self.buffname;
end

function cPowaBuffBase:CheckGroup(group, count, giveReason)
        for groupId = 1, count do
                local present = self:CheckAllAuraSlots(group..groupId, false);
                if (present) then
                        if (self.groupany == true) then
                                PowaAuras:UnitTestDebug("CheckGroup("..group..") Present!");
                                if (not giveReason) then return true; end
                                return true, group..groupId .." has "..self.auraType.." "..self.buffname;
                        end
                elseif (self.groupany==false) then
                        if (not giveReason) then return false; end
                        return false, "Not all in "..group.." has "..self.auraType.." "..self.buffname;
                end
        end
        if (self.groupany==false) then
                PowaAuras:UnitTestDebug("CheckGroup("..group..") All Present!");
                if (not giveReason) then return true; end
                return true, "All in "..group.." has "..self.auraType.." "..self.buffname;
        end
        if (not giveReason) then return false; end
        return false, "No one in "..group.." has "..self.auraType.." "..self.buffname;
end

function cPowaBuffBase:CheckIfShouldShow(giveReason)
        PowaAuras:UnitTestInfo("CheckIfShouldShow ",self.buffAuraType," aura");
        PowaAuras:Debug("Check " .. self.buffAuraType .. " aura");
        local numpm = GetNumPartyMembers();
        local numrm = GetNumRaidMembers();
        --- targets
        if (self.target or self.targetfriend) then
                PowaAuras:UnitTestDebug("on target or friendlytarget");
                return self:CheckAllAuraSlots("target", giveReason);
        end     
        --- focus buff    
        if self.focus then
                PowaAuras:UnitTestDebug("on focus");
                return self:CheckAllAuraSlots("focus", giveReason);
        end             
        --- unit buff    
        if self.optunitn then
                PowaAuras:UnitTestDebug("on unit "..self.unitn);
                return self:CheckAllAuraSlots(self.unitn, giveReason);
        end             
        --- raid buff
        if self.raid then
                PowaAuras:UnitTestDebug("on raid size=", numrm);
                return self:CheckGroup("raid", numrm, giveReason);
        end                     
        --- partybuff    
        if self.party then
                PowaAuras:UnitTestDebug("on party size=", numpm);
                return self:CheckGroup("party", numpm, giveReason);
        end
        
        if (self.groupOrSelf) then --- Group or Self Buff
                PowaAuras:UnitTestDebug("on Group or Self");
                if (numrm>0) then
                        PowaAuras:UnitTestDebug("GoS on raidunit");
                        return self:CheckGroup("raid", numrm, giveReason); -- includes player
                end
                if (numpm>0) then
                        PowaAuras:UnitTestDebug("GoS on partyunit or self");
                        local presentOnSelf, reason = self:CheckAllAuraSlots("player", giveReason);
                        if (presentOnSelf and self.groupany) then
                                if (not giveReason) then return true; end
                                return true, reason;
                        end
                        if (not presentOnSelf and not self.groupany) then
                                if (not giveReason) then return false; end
                                return false, reason;
                        end
                        return self:CheckGroup("party", numpm, giveReason);
                end
                PowaAuras:UnitTestDebug("GoS on player");
                return self:CheckAllAuraSlots("player", giveReason);
        end
                        
        --- player buff    

        PowaAuras:Debug("on player");
        return self:CheckAllAuraSlots("player", giveReason);
end

cPowaBuff = PowaClass(cPowaBuffBase, {buffAuraType = "HELPFUL", auraType="buff"});
cPowaDebuff = PowaClass(cPowaBuffBase, {buffAuraType = "HARMFUL", auraType="debuff"});
cPowaTypeDebuff = PowaClass(cPowaBuffBase, {buffAuraType = "HARMFUL", auraType="debuff type"});

function cPowaTypeDebuff:IsPresent(target, z)
        local removeable;
        if (self.mine) then
                removeable = 1;
        end
        local name, _, texture, count, typeDebuff, _, expirationTime = UnitDebuff(target, z, removeable);
        if (not name) then
                return false;
        end
        PowaAuras:Debug("TypeDebuff IsPresent on ",target,"  buffid ",z,"  removeable ",removeable);
        if (self.mine and typeDebuff==nil) then
                return false;
        end

        PowaAuras:UnitTestDebug("Debuff ",name," type ",typeDebuff);
                
        local typeDebuffName;
        if (typeDebuff ~= nil) then
                typeDebuffName = PowaAuras.Text.DebuffType[typeDebuff];
        end
        local typeDebuffCatName = PowaAuras.Text.DebuffCatType[PowaAuras.DebuffCatSpells[name]];
        if (typeDebuffName == nil and typeDebuffCatName==nil) then
                typeDebuffName = PowaAuras.Text.aucun;
        end

        PowaAuras:UnitTestDebug("typeDebuffName ",typeDebuffName);
        PowaAuras:UnitTestDebug("typeDebuffCatName ",typeDebuffCatName);
        PowaAuras:UnitTestDebug("self.buffname ",self.buffname);
        
        if self:MatchText(typeDebuffName, self.buffname)
        or self:MatchText(typeDebuffCatName, self.buffname) then
                if (self.Timer) then
                        self.Timer.DurationInfo = expirationTime;
                end
                if (self.Stacks) then
                        self.StackCount = count;
                end                     
                if (self.icon == "") then
                        getglobal("PowaIconTexture"):SetTexture(texture);
                        self.icon = getglobal("PowaIconTexture"):GetTexture();
                end
                return true;
        end

        return false;
end


-- This is not really AoE it is periodic damage, could be a DoT or a ground effect damage
cPowaAoE = PowaClass(cPowaAura, {AuraType = "Aoe"});
function cPowaAoE:CheckIfShouldShow(giveReason)
        PowaAuras:Debug("Check AoE");

        if (PowaAuras.DoResetAoe == true) then --- probablement mort, on reset l'effet
                if (not giveReason) then return false; end
                return false, "AoE reset";
        elseif (PowaAuras.AoeAuraAdded ~= "") then --- debuff ajoute
                if self:MatchSpell(PowaAuras.AoeAuraAdded, PowaAuras.AoeAuraTexture, self.buffname) then
                        if (self.icon == "") then
                                getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\Spell_fire_meteorstorm");
                                self.icon = getglobal("PowaIconTexture"):GetTexture();
                        end
                        if (not giveReason) then return true; end
                        return true, "AoE Added "..self.buffname;
                end
        elseif (PowaAuras.AoeAuraFaded ~= "") then 
                if self:MatchSpell(PowaAuras.AoeAuraFaded, PowaAuras.AoeAuraTexture, self.buffname) then
                        if (self.icon == "") then
                          getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\Spell_fire_meteorstorm");
                          self.icon = getglobal("PowaIconTexture"):GetTexture();
                        end
                        if (not giveReason) then return true; end
                        return true, "AoE Faded "..self.buffname;
                end
        end
        
        if (not self.Showing or self.HideRequest) then
                if (not giveReason) then return false; end
                return false, "AoE expired";
        else
                if (not giveReason) then return true; end
                return true, "AoE active";
        end
end

cPowaEnchant = PowaClass(cPowaAura, {AuraType = "Enchants", CanHaveTimer=true, CanHaveTimerOnInverse=true, CanHaveStacks=true, CooldownAura=true});
function cPowaEnchant:GetDuration(durationInfo)
        if (durationInfo and durationInfo > 0) then
                return durationInfo / 1000;
        end
        return 0;
end
function cPowaEnchant:CheckforEnchant(slot, enchantText, textToFind)
        PowaAuras:Debug("Check enchant ("..enchantText..") active in slot",slot);
        --PowaAuras:Message("Check enchant ("..enchantText..") active in slot",slot);
        PowaAuras_Tooltip:SetOwner(UIParent, "ANCHOR_NONE");
        PowaAuras_Tooltip:SetInventoryItem("player", slot);
        PowaAuras:UnitTestDebug("search in tooltip for ", textToFind);                  
        --PowaAuras:Message("search in tooltip for ", textToFind);                      
        for z = 1, PowaAuras_Tooltip:NumLines() do
                PowaAuras:UnitTestDebug("Check tooltip line ",z);
                --PowaAuras:Message("Check tooltip line ",z);
                local textlinel = getglobal("PowaAuras_TooltipTextLeft"..z);
                local textl = textlinel:GetText();
                local text = "";
                if textl then
                        text = text..textl;
                end
                local textliner = getglobal("PowaAuras_TooltipTextRight"..z);
                local textr = textliner:GetText();
                if textr then
                        text = text..textr;
                end
                if (text ~= "") then
                        PowaAuras:UnitTestDebug("| "..text.." |");
                        --PowaAuras:Message("| "..text.." |");
                        if (self:MatchText(text, textToFind)) then
                                PowaAuras_Tooltip:Hide();
                                return true;
                        end
                end
        end     
        PowaAuras_Tooltip:Hide();
        return false;           
end
                                
function cPowaEnchant:SetForEnchant(loc, slot, charges, index)
        PowaAuras:Debug(loc,":found ",self.buffname," in the tooltip!");
        if (self:CheckStacks(charges)) then
                if (self.icon == "") then
                        getglobal("PowaIconTexture"):SetTexture( GetInventoryItemTexture("player", slot) );
                        self.icon = getglobal("PowaIconTexture"):GetTexture();
                end 
                if (self.Stacks) then
                        self.StackCount = count;
                end                     
                return true;
        end
        return false;
end
                
function cPowaEnchant:CheckIfShouldShow(giveReason)
        PowaAuras:Debug("Check weapon enchant");
        local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo();

        local checkMain = true;
        local checkOff = true;
        for pword in string.gmatch(self.buffname, "[^/]+") do
                if (pword==PowaAuras.Text.mainHand) then
                        checkMain = true;
                        checkOff = false;
                elseif (pword==PowaAuras.Text.offHand) then
                        checkOff = true;
                        checkMain = false;
                else
                        if (hasMainHandEnchant and checkMain) then              
                                if (self:CheckforEnchant(16, PowaAuras.Text.mainHand, pword)) then
                                        if (self:SetForEnchant("MH", 16, mainHandCharges, 1)) then
                                                if (self.Timer) then
                                                        self.Timer.DurationInfo = mainHandExpiration;
                                                end
                                                if (self.Stacks) then
                                                        self.StackCount = mainHandCharges;
                                                end                     
                                                if (not giveReason) then return true; end
                                                return true, "Main Hand "..self.buffname.." enchant found";
                                        end
                                end                     
                        end
                        if (hasOffHandEnchant and checkOff) then
                                if (self:CheckforEnchant(17, PowaAuras.Text.offHand, pword)) then
                                        if (self:SetForEnchant("OH", 17, offHandCharges, 2)) then
                                                if (self.Timer) then
                                                        self.Timer.DurationInfo = offHandExpiration;
                                                end             
                                                if (self.Stacks) then
                                                        self.StackCount = offHandCharges;
                                                end                     
                                                if (not giveReason) then return true; end
                                                return true, "Off Hand "..self.buffname.." enchant found";
                                        end
                                end     
                        end
                end
        end
        if (not giveReason) then return false; end
        return false, "No enchant found on weapons";
end

cPowaCombo = PowaClass(cPowaAura, {AuraType = "Combo", CanHaveStacks=true});
function cPowaCombo:CheckIfShouldShow(giveReason)
        if (not(PowaAuras.playerclass == "ROGUE" or (PowaAuras.playerclass=="DRUID" and GetShapeshiftForm()==3))) then
                return nil, "You do not use combo points";
        end
        PowaAuras:Debug("Check Combos");
        local nCombo = tostring(GetComboPoints("player"));
        PowaAuras:UnitTestDebug("nCombo=", nCombo, " self.buffname=", self.buffname);
        if self:MatchText(nCombo, self.buffname) then
                if (self.icon == "") then
                        getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\inv_sword_48");
                        self.icon = getglobal("PowaIconTexture"):GetTexture();
                end
                if (self.Stacks) then
                        self.StackCount = nCombo;
                end                     
                if (not giveReason) then return true; end
                return true, "Combo points "..nCombo.." match "..self.buffname;
        end
        if (not giveReason) then return false; end
        return false, "Combo points "..nCombo.." no match with "..self.buffname;
end

cPowaActionReady = PowaClass(cPowaAura, {AuraType = "Actions", CanHaveTimer=true, CanHaveTimerOnInverse=true, CooldownAura=true});
function cPowaActionReady:CheckIfShouldShow(giveReason)
        PowaAuras:Debug("Check Action / Button:", self.slot);
        if (not self.slot or self.slot == 0) then 
                if (not giveReason) then return false; end
                return false, "Action not set"; 
        end 

        local isUsable = IsUsableAction(self.slot);
        local cdstart, cdduration, enable = GetActionCooldown(self.slot);
        PowaAuras:UnitTestDebug("cdstart= ",cdstart," duration= ",cdduration);
        if (cdduration > 0.2 and cdduration < 1.7 and self.gcd == false) then
                if (isUsable == 1) then --- utilisable, pas de cooldown
                        if (not giveReason) then return true; end
                        return true, "Action Ready";
                end
        else
                if (isUsable == 1 and cdstart == 0) then
                        if (not giveReason) then return true; end
                        return true, "Action Ready";
                end
        end
        if (self.Timer) then
                if (enable>0) then
                        self.Timer.DurationInfo = cdstart + cdduration;
                else
                        self.Timer.DurationInfo = 0;
                end
        end             
        if (not giveReason) then return false; end
        return false, "Action Not Ready, on cooldown";
end

cPowaOwnSpell = PowaClass(cPowaAura, {AuraType = "OwnSpells", CanHaveTimer=true, CanHaveTimerOnInverse=true, CooldownAura=true});
function cPowaOwnSpell:CheckIfShouldShow(giveReason)
        PowaAuras:Debug("Check Spell:", self.buffname);
        --PowaAuras:Message("Check Spell:", self.buffname);
        local reason = "";
        for pword in string.gmatch(self.buffname, "[^/]+") do
                local spellName, spellIcon = self:GetSpellNameFromMatch(pword);
                if (self.icon == "") then
                        if (not spellIcon) then
                                _, _, spellIcon = GetSpellInfo(spellName);
                        end
                        if (spellIcon) then
                                getglobal("PowaIconTexture"):SetTexture(spellIcon);
                                self.icon = getglobal("PowaIconTexture"):GetTexture();
                        end
                end
                local show = false;
                local cdstart, cdduration, enabled = GetSpellCooldown(spellName);
                PowaAuras:UnitTestDebug("cdstart= ",cdstart," duration= ",cdduration," enabled= ",enabled);
                --PowaAuras:Message("cdstart= ",cdstart," duration= ",cdduration," enabled= ",enabled);
                if (enabled) then
                        local isUsable = IsUsableSpell(spellName);
                        if (cdduration > 0.2 and cdduration < 1.7 and self.gcd == false) then
                                show = (isUsable == 1);
                        else
                                show = (isUsable == 1 and cdstart == 0);
                        end     
                        --PowaAuras:Message("show= ",show," self.Timer= ",self.Timer);
                        if (show) then
                                --self.duration = math.max(cdstart + cdduration - GetTime(), 0)
                                if (not giveReason) then return true; end
                                return true, "Spell "..spellName.." usable";
                        else
                                if (self.Timer) then
                                        self.Timer.DurationInfo = cdstart + cdduration;
                                        --PowaAuras:Message("Set DurationInfo= ",self.Timer.DurationInfo);
                                end
                                if (giveReason) then
                                        reason = reason..spellName.." not usable ";
                                end
                        end
                elseif (giveReason) then
                        reason = reason..spellName.." not enabled "
                end
        end
        if (not giveReason) then return false; end
        if (reason == "") then
                return false, "Spell "..self.buffname.." not found";
        end
        return false, reason
end

cPowaAuraStats = PowaClass(cPowaAura);
function cPowaAuraStats:AddEffect(i)
  if not self.target 
  and not self.targetfriend 
  and not self.party 
  and not self.raid 
  and not self.focus
  and not self.optunitn then
                table.insert(PowaAuras.AurasByType[self.ValueName], i);
        end
        if self.optunitn then
                table.insert(PowaAuras.AurasByType["NamedUnit"..self.ValueName], i);
        end
        if self.focus then     
                table.insert(PowaAuras.AurasByType["Focus"..self.ValueName], i);
        end
        if (self.target or self.targetfriend) then --- TargetHealth
                table.insert(PowaAuras.AurasByType["Target"..self.ValueName], i);
        end
        if self.party then
                table.insert(PowaAuras.AurasByType["Party"..self.ValueName], i);
        end
        if self.raid then
                table.insert(PowaAuras.AurasByType["Raid"..self.ValueName], i);
        end
end
function cPowaAuraStats:CheckUnit(unit)
        PowaAuras:Debug("CheckUnit " .. unit);
        if (not self:IsCorrectPowerType(unit)) then
                PowaAuras:UnitTestDebug("Correct powertype " ,self:IsCorrectPowerType(unit));
                return nil;
        end                     
        if (UnitIsDeadOrGhost(unit)) then
                PowaAuras:UnitTestDebug("Correct powertype dead ", UnitIsDeadOrGhost(unit));
                return false;
        end                     

        local curValue = self:UnitValue(unit);
        local maxValue = self:UnitValueMax(unit);
        PowaAuras:UnitTestDebug("curValue=", curValue, " maxValue=", maxValue);
        if (curValue==nil or maxValue==nil) then return false; end

        local curpercenthp = (curValue / maxValue) * 100;
        if self.thresholdinvert then 
                thresholdvalidate = (curpercenthp > self.threshold);
        else
                thresholdvalidate = (curpercenthp < self.threshold)
        end     
        if (thresholdvalidate) then
                if (self.icon == "") then
                        getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\Spell_fire_meteorstorm");
                        self.icon = getglobal("PowaIconTexture"):GetTexture();
                end
                return true;
        end
        return false;
end

function cPowaAuraStats:CheckIfShouldShow(giveReason)
        PowaAuras:Debug("Check Stat "..self.ValueName);
        return self:CheckAllUnits(giveReason);
end


cPowaHealth = PowaClass(cPowaAuraStats, {ValueName = "Health", MatchReason="Health low", NoMatchReason="Health not low enough"});
function cPowaHealth:IsCorrectPowerType(unit)
        return true;
end
function cPowaHealth:UnitValue(unit)
        return UnitHealth(unit);
end
function cPowaHealth:UnitValueMax(unit)
        return UnitHealthMax(unit);
end


cPowaMana = PowaClass(cPowaAuraStats, {ValueName = "Mana", MatchReason="Mana low", NoMatchReason="Mana not low enough"});
function cPowaMana:IsCorrectPowerType(unit)
        local powerType = UnitPowerType(unit);
        return (powerType and powerType == 0);
end
function cPowaMana:UnitValue(unit)
        PowaAuras:Debug("Mana UnitValue for ", unit);
        return UnitPower(unit);
end
function cPowaMana:UnitValueMax(unit)
        PowaAuras:Debug("Mana UnitValueMax for ", unit);
        return UnitPowerMax(unit);
end

cPowaEnergyRagePower = PowaClass(cPowaMana, {ValueName = "RageEnergy", MatchReason="EnergyRagePower low", NoMatchReason="EnergyRagePower not low enough"});
function cPowaEnergyRagePower:IsCorrectPowerType(unit)
        local powerType = UnitPowerType(unit);
        return (powerType and powerType > 0);
end

cPowaAggro = PowaClass(cPowaAura, {ValueName = "Aggro", MatchReason="has aggro", NoMatchReason="does not have aggro"});
function cPowaAggro:AddEffect(i)

        if not self.target 
   and not self.targetfriend 
   and not self.party
   and not self.raid 
   and not self.focus
   and not self.optunitn then --- self Aggro
        table.insert(PowaAuras.AurasByType.Aggro, i);
        end
        if self.party then --- party Aggro
                table.insert(PowaAuras.AurasByType.PartyAggro, i);
        end
        if self.raid then --- raid Aggro
                table.insert(PowaAuras.AurasByType.RaidAggro, i);
        end
end

function cPowaAggro:CheckUnit(unit)
        --PowaAuras:Message(unit," UnitThreatSituation=", UnitThreatSituation(unit));
        return (UnitThreatSituation(unit) or -1)> 0;
end     
function cPowaAggro:CheckIfShouldShow(giveReason)
        if (self.icon == "") then
                getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\Ability_Warrior_EndlessRage");
                self.icon = getglobal("PowaIconTexture"):GetTexture();
        end
        PowaAuras:Debug("Check Aggro status");
        return self:CheckAllUnits(giveReason);
end

cPowaPvP = PowaClass(cPowaAura, {MatchReason="PvP flag set", NoMatchReason="PvP flag not set"});

function cPowaPvP:AddEffect(i)
        if not self.target 
  and not self.targetfriend 
  and not self.party
        and not self.raid 
        and not self.focus
  and not self.optunitn then --- self pvp flag
                table.insert(PowaAuras.AurasByType.PvP, i);
        end
        if (self.target or self.targetfriend) then --- target flag
                table.insert(PowaAuras.AurasByType.TargetPvP, i);
        end
        if self.party then --- party pvp flagged
                table.insert(PowaAuras.AurasByType.PartyPvP, i);
        end
        if self.raid then --- raid pvp flagged
                table.insert(PowaAuras.AurasByType.RaidPvP, i);
        end
end
function cPowaPvP:CheckUnit(unit)
        return UnitIsPVP(unit);
end     
function cPowaPvP:CheckIfShouldShow(giveReason)
        PowaAuras:Debug("Check PvP Flag");
        return self:CheckAllUnits(giveReason);
end


cPowaSpellAlert = PowaClass(cPowaAura);

function cPowaSpellAlert:AddEffect(i)
        if not self.target and not self.focus then --- any enemy casts
                table.insert(PowaAuras.AurasByType.Spells, i);
        end
        if self.target then --- target casts
                table.insert(PowaAuras.AurasByType.TargetSpells, i);
        end
        if self.focus then --- focus casts
                table.insert(PowaAuras.AurasByType.FocusSpells, i);
        end
end

function cPowaSpellAlert:CreateSpellFrame(endtime, spellicon)
        local tempicon;
        if (self.owntex == true) then
                getglobal("PowaIconTexture"):SetTexture(spellicon);
                tempicon = getglobal("PowaIconTexture"):GetTexture();
                if (self.icon ~= tempicon) then
                        self.icon = tempicon;
                end
        end
        if (self.icon == "") then
          getglobal("PowaIconTexture"):SetTexture(spellicon);
          self.icon = getglobal("PowaIconTexture"):GetTexture();
        end
end

function cPowaSpellAlert:GetDuration(durationInfo)
        if (durationInfo and durationInfo > 0) then
                return durationInfo / 1000;
        end
        return 0;
end

function cPowaSpellAlert:CheckUnit(unit)
        if not UnitExists(unit) or UnitIsDead(unit) or not UnitCanAttack(unit, "player") then
                PowaAuras:UnitTestDebug(unit, " exists=", UnitExists(unit), " dead=", UnitIsDeadOrGhost(unit), " hostile=", UnitCanAttack(unit, "player"));
                return false;
        end
        local spellname, _, _, spellicon, _, endtime = UnitCastingInfo(unit);
        if not spellname then
                spellname, _, _, spellicon, _, endtime = UnitChannelInfo(unit);
        end
        if not spellname then -- not casting
                PowaAuras:UnitTestDebug(unit, " is not casting");
                return false;
        end
                
        if self:MatchSpell(spellname, spellicon, self.buffname, true) then
                if (self.Timer) then
                        self.Timer.DurationInfo = endtime;
                end
                self:CreateSpellFrame(endtime, spellicon);
                return true;
        end
        
        PowaAuras:UnitTestDebug(unit, " is casting ", spellname, " no match");
        return false;
end     

function cPowaSpellAlert:CheckIfShouldShow(giveReason)
        PowaAuras:Debug("Check if target/focus is casting ", self.buffname);
        
        -- Check self target/focus first
        if (self:CheckUnit("target")) then
                if (not giveReason) then return true; end
                return true, "Target casting "..self.buffname;
        end
        if (self:CheckUnit("focus")) then
                if (not giveReason) then return true; end
                return true, "Focus casting "..self.buffname;
        end     

        --- Scan raid targets
        local numrm = GetNumRaidMembers();
        if numrm > 0 then
                for i=1, numrm do
                        if (self:CheckUnit("raid"..i.."target")) then
                                if (not giveReason) then return true; end
                                return true, "Raid"..i.."Target casting "..self.buffname;
                        end
                end
        else
            -- Scan party targets
                local numpm = GetNumPartyMembers();
                if numpm > 0 then
                        for i=1, numpm do
                                if (self:CheckUnit("party"..i.."target")) then
                                        if (not giveReason) then return true; end
                                        return true, "Party"..i.."Target casting "..self.buffname;
                                end
                        end
                end
        end
        if (not giveReason) then return false; end
        return false, "Nobody's target casting "..self.buffname;
end

cPowaStance = PowaClass(cPowaAura, {AuraType = "Stance"});
function cPowaStance:CheckIfShouldShow(giveReason)
        PowaAuras:Debug("Check Stance");
        local nStance = GetShapeshiftForm(false);
        PowaAuras:UnitTestDebug("nStance = "..tostring(nStance).." / self.stance = "..tostring(self.stance));
        if (nStance == self.stance and self.icon == "") then
                local icon = GetShapeshiftFormInfo(nStance);
                getglobal("PowaIconTexture"):SetTexture(icon);
                self.icon = getglobal("PowaIconTexture"):GetTexture();
        end
        if (nStance == self.stance)then
                if (not giveReason) then return true; end
                return true, "Stances match";
        end
        if (not giveReason) then return false; end
        return false, "Stances don't match";
end


-- Concrete Classes
PowaAuras.AuraClasses = {
        [PowaAuras.BuffTypes.Buff]=cPowaBuff,
        [PowaAuras.BuffTypes.Debuff]=cPowaDebuff,
        [PowaAuras.BuffTypes.TypeDebuff]=cPowaTypeDebuff,
        [PowaAuras.BuffTypes.AoE]=cPowaAoE,
        [PowaAuras.BuffTypes.Enchant]=cPowaEnchant,
        [PowaAuras.BuffTypes.Combo]=cPowaCombo,
        [PowaAuras.BuffTypes.ActionReady]=cPowaActionReady,
        [PowaAuras.BuffTypes.Health]=cPowaHealth,
        [PowaAuras.BuffTypes.Mana]=cPowaMana,
        [PowaAuras.BuffTypes.EnergyRagePower]=cPowaEnergyRagePower,
        [PowaAuras.BuffTypes.Aggro]=cPowaAggro,
        [PowaAuras.BuffTypes.PvP]=cPowaPvP,
        [PowaAuras.BuffTypes.SpellAlert]=cPowaSpellAlert,
        [PowaAuras.BuffTypes.Stance]=cPowaStance,
        [PowaAuras.BuffTypes.OwnSpell]=cPowaOwnSpell,
}

-- Instance concrete class based on type
function PowaAuras:AuraFactory(auraType, id, base)
        local class = self.AuraClasses[auraType];
        if (class) then
                --self:Message("AuraFactory "..tostring(auraType).." id="..tostring(id).." class="..tostring(class));
                if (base == nil) then
                        base = {};
                end
                base.bufftype = auraType;
                return class(id, base);
        end
        self:Message("AuraFactory unknown "..tostring(auraType).." id="..tostring(id)); --OK
        return nil;
end

Compare with Previous | Blame