vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
--[[
  ****************************************************************
        Scrolling Combat Text 5.0

        Author: Grayhoof
        ****************************************************************
        
        Official Site:
                http://grayhoof.wowinterface.com 
        
        ****************************************************************]]
SCT = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceDB-2.0", "AceConsole-2.0", "AceHook-2.0");
        
--embedded libs
local parser = ParserLib:GetInstance("1.1")
        
--Table Constants
SCT.COLORS_TABLE = "COLORS";
SCT.CRITS_TABLE = "CRITS";
SCT.FRAMES_TABLE = "FRAMES";
SCT.FRAMES_DATA_TABLE = "FRAMESDATA";
SCT.FRAME1 = 1;
SCT.FRAME2 = 2;
SCT.MSG = 10;

-- local constants, use lowercase sct
local sct_LastHPPercent = 0;
local sct_LastTargetHPPercent = 0;
local sct_LastManaPercent = 0;
local sct_LastManaFull = 99999;

local arrPowerStrings = {
                [0] = MANA,
                [1] = RAGE,
                [3] = ENERGY
}

local arrShadowOutline = {
        [1] = "",
        [2] = "OUTLINE",
        [3] = "THICKOUTLINE"
}

local arrSpellColors = {
        [SPELL_SCHOOL0_CAP] = {r=1,g=0,b=0},
        [SPELL_SCHOOL1_CAP] = {r=1,g=1,b=0},
        [SPELL_SCHOOL2_CAP] = {r=1,g=.3,b=0},
        [SPELL_SCHOOL3_CAP] = {r=.5,g=1,b=.2},
        [SPELL_SCHOOL4_CAP] = {r=.4,g=.6,b=.9},
        [SPELL_SCHOOL5_CAP] = {r=.4,g=.4,b=.5},
        [SPELL_SCHOOL6_CAP] = {r=.8,g=.8,b=1},
}

SCT.SpellColors = arrSpellColors;

----------------------
--Called on login
function SCT:OnEnable()
        self:RegisterSelfEvents();
end

----------------------
-- called on standby
function SCT:OnDisable()
        self:DisableAll()
end

----------------------
-- Disable all events
function SCT:DisableAll()
        -- no more events to handle
        parser:UnregisterAllEvents("sct")
        self:UnregisterAllEvents()
end

----------------------
-- Show the Option Menu
function SCT:ShowMenu()
        local loaded, message = LoadAddOn("sct_options");
        if (loaded) then
                PlaySound("igMainMenuOpen");
                ShowUIPanel(SCTOptions);
        else
                PlaySound("TellMessage");
                SCT:Print(SCT.LOCALS.Load_Error.." "..message);
        end
end

----------------------
--Hide the Option Menu
function SCT:HideMenu()
        PlaySound("igMainMenuClose");
        HideUIPanel(SCTOptions);
end

----------------------
--Called when Addon loaded
function SCT:OnInitialize()
        
        --default settings
        local default_config = self:GetDefaultConfig();
                
        --slash command setup
        local main = {
                type="group",
                args = {
                        menu = {
                                name = "Menu", type = 'execute',
                    desc = "Display SCT Option Menu",
                    func = function()
                        self:ShowMenu();
                end
                        },
                        reset = {
                                name = "Reset", type = 'execute',
                    desc = "Reset SCT Options to default",
                    func = function()
                        self:Reset();
                end
                        }
                }
        }
        local menu = {
                type = 'execute',
    desc = "Display SCT Option Menu",
    func = function()
        self:ShowMenu();
    end
        }
        local reset = {
                type = 'execute',
    desc = "Reset SCT Options to default",
    func = function()
        self:Reset();
    end
        }
        local cmd = {
                type = 'text',
                name = "Display",
                usage = SCT.LOCALS.DISPLAY_USEAGE,
    desc = "Display a message using SCT",
    get = false,
    set = function(x)
        self:CmdDisplay(x);
    end
        }
        
        --hook chat frame if using event debug
        if SCT.EventDebug then
                for i = 1, 7, 1 do
                        self:Hook(getglobal("ChatFrame" .. i), "AddMessage")
                end
        end
        
        self:RegisterDB("SCT_CONFIG")
        self:RegisterDefaults('profile', default_config )
        
        self:RegisterChatCommand({"/sct"}, main) 
        self:RegisterChatCommand({"/sctmenu"}, menu)
        self:RegisterChatCommand({"/sctreset"}, reset) 
        self:RegisterChatCommand({"/sctdisplay"}, cmd) 
        
        --set to profile by char by default
        if not self.db.char.notFirstTime then 
                self.db.char.notFirstTime = true;
                self:SetProfile("char");
        end
        
        --register with other mods
        self:RegisterOtherMods()
        
        -- Add my options frame to the global UI panel list
        UIPanelWindows["SCTOptions"] = {area = "center", pushable = 0};
        
        --setup animations
        self:AniInit();
        
        --Set Enabled State
        if (self.db.profile["ENABLED"]) then
                self:ToggleActive(true);
                self:Print(SCT.LOCALS.STARTUP);
        else
                self:ToggleActive(false);
        end

end

----------------------
--Hook Function to show event
function SCT:AddMessage(frame, text, r, g, b, id)
    self.hooks[frame].AddMessage.orig(frame, text.." |cff00ff00["..tostring(event).."]|r", r, g, b, id)
end

----------------------
--Reset everything to default
function SCT:Reset()
        self:ResetDB("profile")
        self:HideMenu();
        self:ShowMenu();
        self:ShowExample();
        self:Print(SCT.LOCALS.PROFILE_NEW..AceLibrary("AceDB-2.0").CHAR_ID);
end

----------------------
--Get a value from player config
function SCT:Get(option, table)
        if (table) then
                return self.db.profile[table][option];
        else
                return self.db.profile[option];
        end
end

----------------------
--Set a value in player config
function SCT:Set(option, value, table)
        if (table) then
                self.db.profile[table][option] = value;
        else
                self.db.profile[option] = value;
        end
end

----------------------
--Display for any partial blocks
function SCT:DisplayBlock(blocked)
        SCT:Display_Event("SHOWBLOCK", BLOCK.." ("..blocked..")");
end

----------------------
--Display for any partial absorbs
function SCT:DisplayAbsorb(absorbed)
        SCT:Display_Event("SHOWABSORB", ABSORB.." ("..absorbed..")");
end     

----------------------
-- Event Handler
-- this function parses events that are printed in the combat
-- chat window then displays the health changes
function SCT:OnEvent()                          
        --Player Health
        if (event == "UNIT_HEALTH") then
                if (arg1 == "player") then
                        local warnlevel = self.db.profile["LOWHP"] / 100;
                        local HPPercent = UnitHealth("player") / UnitHealthMax("player");
      if (HPPercent < warnlevel) and (sct_LastHPPercent >= warnlevel) and (not SCT:CheckFD("player")) then
        if (self.db.profile["PLAYSOUND"] and self.db.profile["SHOWLOWHP"]) then
                PlaySoundFile("Sound\\Spells\\bind2_Impact_Base.wav")
        end
        self:Display_Event("SHOWLOWHP", SCT.LOCALS.LowHP.." ("..UnitHealth("player")..")");
      end
      sct_LastHPPercent = HPPercent;
      return;
                end
                return;
                
        --Player Mana
        elseif (event == "UNIT_MANA") or (event == "UNIT_RAGE") or (event == "UNIT_ENERGY")then
                if (arg1 == "player") and (UnitPowerType("player") == 0)then
                        local warnlevel = self.db.profile["LOWMANA"] / 100;
                        local ManaPercent = UnitMana("player") / UnitManaMax("player");
      if (ManaPercent < warnlevel) and (sct_LastManaPercent >= warnlevel) and (not SCT:CheckFD("player")) then
        if (self.db.profile["PLAYSOUND"] and self.db.profile["SHOWLOWMANA"]) then
                PlaySoundFile("Sound\\Spells\\ShaysBell.wav");
        end
        SCT:Display_Event("SHOWLOWMANA", SCT.LOCALS.LowMana.." ("..UnitMana("player")..")");
      end
      sct_LastManaPercent = ManaPercent;
                end
                if (arg1 == "player") and (self.db.profile["SHOWALLPOWER"]) then
                        local ManaFull = UnitMana("player");
                        if (ManaFull > sct_LastManaFull) then
                                self:Display_Event("SHOWPOWER", "+"..ManaFull-sct_LastManaFull.." "..arrPowerStrings[UnitPowerType("player")]);
                        end
                        sct_LastManaFull = ManaFull;
                end
                return;
                
        --Power Change
        elseif (event == "UNIT_DISPLAYPOWER") then
                sct_LastManaFull = UnitMana("player");
                return;
                
        --Player Combat
        elseif (event =="PLAYER_REGEN_DISABLED") then
                self:Display_Event("SHOWCOMBAT", SCT.LOCALS.Combat);
                return;
                
        --Player NoCombat
        elseif (event =="PLAYER_REGEN_ENABLED") then
                self:Display_Event("SHOWCOMBAT", SCT.LOCALS.NoCombat);
                return;
                
        --Player Combo Points
        elseif (event == "PLAYER_COMBO_POINTS") then
                local sct_CP = GetComboPoints();
                if (sct_CP ~= 0) then
                        local sct_CP_Message = sct_CP.." "..SCT.LOCALS.ComboPoint;
                        if (sct_CP == 5) then
                                sct_CP_Message = sct_CP_Message.." "..SCT.LOCALS.FiveCPMessage;
                        end;
                        self:Display_Event("SHOWCOMBOPOINTS", sct_CP_Message);
                end
                return;
        
        --All other combat events       
        elseif (arg1) then
                self:ParseCombat(arg1); 
        end
end

----------------------
-- Displays Parsed info based on type
function SCT:ParseCombat(info)
        --self doesn't work here because of the call from ParserLib
        local self = SCT;
        
        --custom search first
        if (self.db.profile["CUSTOMEVENTS"]) and (not SCT.db.profile["LIGHTMODE"]) and (self:CustomEventSearch(arg1) == true) then
                return;
        end
        
        --Player Skill Gains Here, since its unsupported
        if (event == "CHAT_MSG_SKILL") then
                local target, rank = parser:Deformat(arg1, SKILL_RANK_UP);
                if target then
                        self:Display_Event("SHOWSKILL", target..": "..rank);
                        return;
                end
                return;
        end
        
        --if its not a ParserLib Event, then end
        if (type(info) ~= "table") then
                return;
        end
        
        --outgoing heals, done first since its only thing blizzard events don't do
        if (info.type == "heal" and info.victim ~= ParserLib_SELF) then
                --heal filter
                if (info.amount < self.db.profile["HEALFILTER"]) then return end;
                --outgoing heals, ignore dots
                if (info.source == ParserLib_SELF and not info.isDOT) then
                        if (self.db.profile["SHOWOVERHEAL"]) then
                                info.amount = self:GetOverheal(info.victim, info.amount);
                        end
                        self:Display_Event("SHOWSELFHEAL", info.victim..": +"..info.amount, info.isCrit);
                end
                return;
        end
        
        --if in light mode, end here
        if (self.db.profile["LIGHTMODE"]) then
                return;
        end
        
        -- Environmental
        if (info.type == "environment") then
                if (info.victim == ParserLib_SELF) then
                        if( info.damageType == "fire" or info.damageType == "lava" or info.damageType == "slime") then
                                self:Display_Event("SHOWSPELL", "-"..info.amount, nil, nil, info.amountResist   );
                        else
                                self:Display_Event("SHOWHIT", "-"..info.amount);
                        end
                        if(info.amountAbsorb) then
                                self:DisplayAbsorb(info.amountAbsorb);
                        end
                end

        --Hits (melee, spell, etc..)
        elseif (info.type == "hit") then
                if (info.victim == ParserLib_SELF) then
                        if (info.skill == ParserLib_MELEE) then
                                self:Display_Event("SHOWHIT", "-"..info.amount, info.isCrit);
                        else
                                self:Display_Event("SHOWSPELL", "-"..info.amount, info.isCrit, info.element, info.amountResist);
                        end
                        if( info.amountAbsorb) then
                                self:DisplayAbsorb(info.amountAbsorb);
                        end
                        if( info.amountBlock) then
                                self:DisplayBlock(info.amountBlock);
                        end
                end             
        
        --Miss Events
        elseif (info.type == "miss") then
                if (info.victim == ParserLib_SELF) then
                        if (info.missType == "miss") then
                                self:Display_Event("SHOWMISS", MISS, nil, nil, nil, nil, SCT.LOCALS.TARGET.." "..MISS);
                        elseif (info.missType == "dodge") then
                                self:Display_Event("SHOWDODGE", DODGE, nil, nil, nil, nil, YOU.." "..DODGE);
                        elseif (info.missType == "block") then
                                self:Display_Event("SHOWBLOCK", BLOCK, nil, nil, nil, nil, YOU.." "..BLOCK);
                        elseif (info.missType == "deflect") then
                                self:Display_Event("SHOWABSORB", DEFLECT, nil, nil, nil, nil, YOU.." "..DEFLECT);
                        elseif (info.missType == "immune") then
                                self:Display_Event("SHOWABSORB", IMMUNE, nil, nil, nil, nil, YOU.." "..IMMUNE);
                        elseif (info.missType == "evade") then
                                self:Display_Event("SHOWABSORB", EVADAE, nil, nil, nil, nil, YOU.." "..EVADE);
                        elseif (info.missType == "parry") then
                                self:Display_Event("SHOWPARRY", PARRY, nil, nil, nil, nil, YOU.." "..PARRY);
                        elseif (info.missType == "resist") then
                                self:Display_Event("SHOWRESIST", RESIST, nil, nil, nil, nil, YOU.." "..RESIST);
                        elseif (info.missType == "reflect") then
                                self:Display_Event("SHOWABSORB", REFLECT, nil, nil, nil, nil, YOU.." "..REFLECT);
                        elseif (info.missType == "absorb") then
                                self:Display_Event("SHOWABSORB", ABSORB, nil, nil, nil, nil, YOU.." "..ABSORB);
                        end
                end
        
        --Gains
        elseif (info.type == "gain") then
                if (info.victim == ParserLib_SELF) and (not self.db.profile["SHOWALLPOWER"]) then
                        self:Display_Event("SHOWPOWER", "+"..info.amount.." "..info.attribute);
                end
                        
        --Leech
        elseif (info.type == "leech") and (not self.db.profile["SHOWALLPOWER"]) then
                if (info.sourceGained == ParserLib_SELF) then
                        self:Display_Event("SHOWPOWER", "+"..info.amountGained.." "..info.attributeGained);
                end
        
        --buff
        elseif (info.type == "buff") then
                if (info.victim == ParserLib_SELF) then
                        self:Display_Event("SHOWBUFF", "["..info.skill.."]", nil, nil, nil, nil, arg1);
                end     
        
        --debuff
        elseif (info.type == "debuff") then
                if (info.victim == ParserLib_SELF) then
                        if (info.amountRank) then
                                self:Display_Event("SHOWDEBUFF", "("..info.skill.." "..info.amountRank..")", nil, nil, nil, nil, arg1);
                        else
                                self:Display_Event("SHOWDEBUFF", "("..info.skill..")", nil, nil, nil, nil, arg1);
                        end
                end
                        
        --healing in/out
        elseif (info.type == "heal") then
                --heal filter
                if (info.amount < self.db.profile["HEALFILTER"]) then return end;
                --self heals
                if (info.victim == ParserLib_SELF and info.source == ParserLib_SELF) then
                        if (self.db.profile["SHOWOVERHEAL"]) then
                                info.amount = self:GetOverheal("player", info.amount);
                        end
                        self:Display_Event("SHOWHEAL", "+"..info.amount, info.isCrit, nil, nil, info.skill);
                --incoming heals
                elseif (info.victim == ParserLib_SELF) then
                        self:Display_Event("SHOWHEAL", "+"..info.amount, info.isCrit, nil, nil, info.source);
                end
        end
end

----------------------
--Handle Blizzard events
function SCT:BlizzardCombatTextEvent()
        --Normal Events
        if (arg1=="SPELL_ACTIVE") then
                self:Display_Event("SHOWEXECUTE", arg2.."!");
        elseif (arg1=="FACTION") then
                if ( tonumber(arg3) < 0 ) then
                        self:Display_Event("SHOWREP", "-"..arg3.." "..REPUTATION.." ("..arg2..")");
                else
                        self:Display_Event("SHOWREP", "+"..arg3.." "..REPUTATION.." ("..arg2..")");
                end
        elseif (arg1=="HONOR_GAINED") then
                self:Display_Event("SHOWHONOR", "+"..arg2.." "..HONOR);
        elseif (arg1=="AURA_END") then
                self:Display_Event("SHOWFADE", "-["..arg2.."]",nil,nil,nil,nil,format(AURAREMOVEDSELF, arg2));
        elseif (arg1=="AURA_END_HARMFUL") then
                if (self.db.profile["SHOWFADE"]) then
                        self:Display_Event("SHOWDEBUFF", "-("..arg2..")",nil,nil,nil,nil,format(AURAREMOVEDSELF, arg2));
                end
        elseif (arg1=="EXTRA_ATTACKS") then
                if ( tonumber(arg2) > 1 ) then
                        self:Display_Event("SHOWEXECUTE", self.LOCALS.ExtraAttack.."("..arg2..")");
                else
                        self:Display_Event("SHOWEXECUTE", self.LOCALS.ExtraAttack);
                end
        end
        
        --if not in light mode, end here
        if (not self.db.profile["LIGHTMODE"]) then
                return;
        end
        
        --Light Mode Event
        if ( arg1 == "DAMAGE_CRIT" ) then
                self:Display_Event("SHOWHIT", "-"..arg2, 1);
        elseif ( arg1 == "DAMAGE" ) then
                self:Display_Event("SHOWHIT", "-"..arg2);
        elseif ( arg1 == "SPELL_DAMAGE" ) then
                self:Display_Event("SHOWSPELL", "-"..arg2);
        elseif ( arg1 == "AURA_START" ) then
                self:Display_Event("SHOWBUFF", "["..arg2.."]");
        elseif ( arg1 == "AURA_START_HARMFUL" ) then
                self:Display_Event("SHOWDEBUFF", "("..arg2..")");
        elseif ( arg1 == "HEAL" or arg1 == "PERIODIC_HEAL") then
                --heal filter
                if (tonumber(arg3) < tonumber(self.db.profile["HEALFILTER"])) then return end;
                if ( UnitName("player") ~= arg2 ) then
                        self:Display_Event("SHOWHEAL", "+"..arg3, nil, nil, nil, arg2);
                else
                        self:Display_Event("SHOWHEAL", "+"..arg3);
                end
        elseif ( arg1 == "HEAL_CRIT" ) then
                --heal filter
                if (tonumber(arg3) < tonumber(self.db.profile["HEALFILTER"])) then return end;
                if ( UnitName("player") ~= arg2 ) then
                        self:Display_Event("SHOWHEAL", "+"..arg3, 1, nil, nil, arg2);
                else
                        self:Display_Event("SHOWHEAL", "+"..arg3, 1);
                end
        elseif ( arg1 == "MANA" or arg1 == "RAGE" or arg1 == "ENERGY") then
                if (not self.db.profile["SHOWALLPOWER"]) then
                        self:Display_Event("SHOWPOWER", "+"..arg2.." "..getglobal(arg1));
                end
        elseif ( arg1 == "MISS" or arg1 == "SPELL_MISSED") then
                self:Display_Event("SHOWMISS", MISS, nil, nil, nil, nil, SCT.LOCALS.TARGET.." "..MISS);
        elseif ( arg1 == "EVADE" or arg1 == "SPELL_EVADED") then
                self:Display_Event("SHOWABSORB", EVADAE, nil, nil, nil, nil, YOU.." "..EVADE);
        elseif ( arg1 == "DODGE" or arg1 == "SPELL_DODGED" ) then
                self:Display_Event("SHOWDODGE", DODGE, nil, nil, nil, nil, YOU.." "..DODGE);
        elseif ( arg1 == "PARRY" or arg1 == "SPELL_PARRIED") then
                self:Display_Event("SHOWPARRY", PARRY, nil, nil, nil, nil, YOU.." "..PARRY);
        elseif ( arg1 == "IMMUNE" or arg1 == "SPELL_IMMUNE") then
                self:Display_Event("SHOWABSORB", IMMUNE, nil, nil, nil, nil, YOU.." "..IMMUNE);
        elseif ( arg1 == "DEFLECT" or arg1 == "SPELL_DEFLECTED") then
                self:Display_Event("SHOWABSORB", DEFLECT, nil, nil, nil, nil, YOU.." "..DEFLECT);
        elseif ( arg1 == "SPELL_REFLECTED") then
                self:Display_Event("SHOWABSORB", REFLECT, nil, nil, nil, nil, YOU.." "..REFLECT);
        elseif ( arg1 == "BLOCK" or arg1 == "SPELL_BLOCKED") then
                if ( arg3 ) then
                        if (arg1 == "SPELL_BLOCKED") then
                                self:Display_Event("SHOWSPELL", "-"..arg2);
                        else
                                self:Display_Event("SHOWHIT", "-"..arg2);
                        end
                        self:DisplayBlock(arg3)
                else
                        self:Display_Event("SHOWBLOCK", BLOCK, nil, nil, nil, nil, YOU.." "..BLOCK);
                end
        elseif ( arg1 == "ABSORB" or arg1 == "SPELL_ABSORBED" ) then
                if ( arg3 ) then
                        if (arg1 == "SPELL_ABSORBED") then
                                self:Display_Event("SHOWSPELL", "-"..arg2);
                        else
                                self:Display_Event("SHOWHIT", "-"..arg2);
                        end
                        self:DisplayAbsorb(arg3)
                else
                        self:Display_Event("SHOWABSORB", ABSORB, nil, nil, nil, nil, YOU.." "..ABSORB);
                end
        elseif ( arg1 == "RESIST" or arg1 == "SPELL_RESISTED" ) then
                if ( arg3 ) then
                        if (arg1 == "SPELL_RESISTED") then
                                self:Display_Event("SHOWSPELL", "-"..arg2, nil, nil, arg3);
                        else
                                self:Display_Event("SHOWHIT", "-"..arg2, nil, nil, arg3);
                        end
                else
                        self:Display_Event("SHOWRESIST", RESIST, nil, nil, nil, nil, YOU.." "..RESIST);
                end
        end
end

----------------------
--Find a custom capture event message
function SCT:CustomEventSearch(arg1)
        local strTempMessage, currentcolor, table, classfound, key, key2, class, value, i;
        local carg1, carg2, carg3, carg4, carg5;
        --cache it index order
        if (SCT.CustomEvents == nil) then
                SCT.CustomEvents = {};
                for key, value in self:PairsByKeys(SCT.EventConfig) do
                        tinsert(SCT.CustomEvents, value);
                end
        end
        for key, value in SCT.CustomEvents do
                --default class found to true
                classfound = true;
                --check if they want to see it for this class
                if (value.class) then
                        --if want to filter by class, default to false
                        classfound = false;
                        for key2, class in value.class do
                                if (strlower(UnitClass("player")) == strlower(class)) then
                                        classfound = true;
                                        break;
                                end
                        end
                end
                --if ok
                if (classfound) then
                        for carg1, carg2, carg3, carg4, carg5 in string.gfind(arg1, value.search) do
                                strTempMessage = value.name;
                                --if there are capture args
                                if ((value.argcount) and (value.argcount > 0) and (value.argcount < 6)) then
                                        table = {carg1, carg2, carg3, carg4, carg5}
                                        --loop though each capture arg. if it exists replace the display position with it
                                        for i = 1, value.argcount do
                                                if (table[i]) then
                                                        strTempMessage, _ = string.gsub(strTempMessage, "*"..i, table[i]);
                                                end
                                        end
                                end
                                --get color
                                currentcolor = {r = 1.0, g = 1.0, b = 1.0};
                                if (value.r and value.g and value.b) then
                                        currentcolor.r,currentcolor.g,currentcolor.b = value.r,value.g,value.b;
                                end
                                --set msg
                                if (value.ismsg) then value.ismsg = SCT.MSG end;
                                --play sound
                                if (value.sound) then PlaySound(value.sound) end;
                                --play soundwave
                                if (value.soundwave) then PlaySoundFile(value.soundwave) end;
                                --display
                                self:DisplayCustomEvent(strTempMessage, currentcolor, value.iscrit, value.ismsg, value.anitype);
                                return true;                            
                        end
                end
        end
        return false;
end

----------------------
--Display for mainly combat events
--Mainly used for short messages
function SCT:Display_Event(option, msg1, crit, damagetype, resisted, target, msg2)
        local rbgcolor, showcrit, showmsg, event;
        --if option is on
        if (self.db.profile[option]) then
                --get options
                rbgcolor = self.db.profile[self.COLORS_TABLE][option];
                showcrit = self.db.profile[self.CRITS_TABLE][option];
                showmsg = self.db.profile[self.FRAMES_TABLE][option] or 1;
                --if damage type
                if ((damagetype) and (self.db.profile["SPELLTYPE"])) then
                        msg1 = msg1.." ("..damagetype..")";
                end
                --if spell color
                if ((damagetype) and (self.db.profile["SPELLCOLOR"])) then
                        rbgcolor = self.SpellColors[damagetype] or rbgcolor;
                end
                --if resisted
                if ((resisted) and (self.db.profile["SHOWRESIST"])) then
                        msg1 = msg1.." ("..resisted.." "..ERR_FEIGN_DEATH_RESISTED..")";
                end
                --if target label
                if ((target) and (self.db.profile["SHOWTARGETS"])) then
                        msg1 = msg1.." ("..target..")";
                end
                --if messages
                if (showmsg == SCT.MSG) then
                        --if 2nd msg
                        if (msg2) then msg1 = msg2 end;
                        --display message
                        self:DisplayMessage( msg1, rbgcolor );
                else
                        event = "event";
                        --set event type
                        if (option == "SHOWHIT" or option == "SHOWSPELL" or option == "SHOWHEAL" or option == "SHOWSELFHEAL") then
                                event = "damage";
                        end
                        --see if crit override
                        if (showcrit) then crit = 1 end;
                        --display
                        self:DisplayText(msg1, rbgcolor, crit, event, showmsg);
                end
        end
end

----------------------
--Display the Text based on message flag for custom events
function SCT:DisplayCustomEvent(msg1, color, iscrit, ismsg, anitype)
        if (ismsg) then
                self:DisplayMessage( msg1, color );
        else
                self:DisplayText(msg1 , color, iscrit, "event", 1, anitype);
        end     
end

----------------------
--Displays a message at the top of the screen
function SCT:DisplayMessage(msg, color)
                SCT_MSG_FRAME:AddMessage(msg, color.r, color.g, color.b, 1);
end

----------------------
--Display text from a command line
function SCT:CmdDisplay(msg)    
        local message = nil;
        local colors = nil;
        --If there are not parameters, display useage
        if string.len(msg) == 0 then
                self:DisplayUseage();
        --Get message anf colors if quotes used
        elseif string.sub(msg,1,1) == "'" then
                local location = string.find(string.sub(msg,2),"'")
                if location and (location>1) then
                        message = string.sub(msg,2,location)
                        colors = string.sub(msg,location+1);
                end
        --Get message anf colors if single word used
        else
                local idx = string.find(msg," ");
                if (idx) then
                        message = string.sub(msg,1,idx-1);
                        colors = string.sub(msg,idx+1);
                else
                        message = msg;
                end
        end
        --if they sent colors, grab them
        local firsti, lasti, red, green, blue = nil;
        if (colors ~= nil) then
                firsti, lasti, red, green, blue = string.find (colors, "(%w+) (%w+) (%w+)");
        end
  local color = {r = 1.0, g = 1.0, b = 1.0};
        --if they sent 3 colors use them, else use default white
  if (red) and (green) and (blue) then   
        color.r,color.g,color.b = (tonumber(red)/10),(tonumber(green)/10),(tonumber(blue)/10);
  end
  self:DisplayText(message, color, nil, "event", 1);
end

-------------------------
--Set the font of an object using msg vars
function SCT:SetMsgFont(object)
        --set font
        object:SetFont(SCT.LOCALS.FONTS[self.db.profile[self.FRAMES_DATA_TABLE][SCT.MSG]["MSGFONT"]].path,
                                                                 self.db.profile[self.FRAMES_DATA_TABLE][SCT.MSG]["MSGSIZE"], 
                                                                 arrShadowOutline[self.db.profile[self.FRAMES_DATA_TABLE][SCT.MSG]["MSGFONTSHADOW"]]);
        --reset size of allow 3 messages
        object:SetHeight(self.db.profile[self.FRAMES_DATA_TABLE][SCT.MSG]["MSGSIZE"] * 4) 
        --Set Fade Duration
        if (object.SetFadeDuration) then
                object:SetFadeDuration(1);
        end
end

-------------------------
--Set the font of the built in damage font
function SCT:SetDmgFont()
        if (SCT.db.profile["DMGFONT"]) then
                DAMAGE_TEXT_FONT = SCT.LOCALS.FONTS[SCT.db.profile[SCT.FRAMES_DATA_TABLE][SCT.FRAME1]["FONT"]].path;
        end
end

-------------------------
--Set the font of an object
function SCT:SetFontSize(object, font, textsize, fontshadow)
        object:SetFont(SCT.LOCALS.FONTS[font].path, textsize, arrShadowOutline[fontshadow]);
end

-------------------------
--Determine if a hunter is FD'ing
--Code taken from CTRA
function SCT:CheckFD(unit)
        if ( UnitClass(unit) ~= SCT.LOCALS.HUNTER ) then
                return;
        end
        local hasFD;
        local num, buff = 0, UnitBuff(unit, 1);
        while ( buff ) do
                if ( buff == "Interface\\Icons\\Ability_Rogue_FeignDeath" ) then
                        hasFD = 1;
                        break;
                end
                num = num + 1;
                buff = UnitBuff(unit, num+1);
        end
        if ( hasFD ) then
                return true;
        else
                return false;
        end
end

-------------------------
--Return the unit if for a given  target
function SCT:GetTargetUnit(target)
        local unit;
        if (target == "player") then
                return "player";
        end
        if (target == UnitName('pet'))then
          return "pet";
        end
        for i = 1, GetNumRaidMembers(), 1 do
                if ( UnitName("raid" .. i) and UnitName("raid" .. i) == target ) then
                        return "raid"..i;
                end
        end
        for i = 1, GetNumPartyMembers(), 1 do
                if ( UnitName("party" .. i) and UnitName("party" .. i) == target ) then
                        return "party"..i;
                end
        end
end

-------------------------
--Return the amount the target is overhealed
function SCT:GetOverheal(target, damage)
        local unit = self:GetTargetUnit(target);
        if unit then
                local lost = UnitHealthMax(unit)-UnitHealth(unit);
        local overheal = damage - lost;
        if (overheal > 0) then
                damage = lost.." {"..overheal.."}";
        end
  end
  return damage;
end

-------------------------
--Regsiter SCT with other mods
function SCT:RegisterOtherMods()
        -- myAddOns support
        if(myAddOnsFrame_Register) then
                local SCTDetails = {
                        name = "sct",
                        version = SCT.Version,
                        optionsframe = "SCTOptions",
                        category = MYADDONS_CATEGORY_COMBAT
                };
                myAddOnsFrame_Register(SCTDetails);
        end
        
        --Cosmos support
        if ( EarthFeature_AddButton ) then
                EarthFeature_AddButton(
                   {
                      id="SCT";
                      name=SCT.LOCALS.SCT_CB_NAME;
                      text=SCT.LOCALS.SCT_CB_NAME;
                      subtext=SCT.LOCALS.SCT_CB_SHORT_DESC;
                      helptext=SCT.LOCALS.SCT_CB_LONG_DESC;
                      icon=SCT.LOCALS.SCT_CB_ICON;
                      callback=SCT.ShowMenu;
                   }
                );
        elseif (Cosmos_RegisterButton) then
                Cosmos_RegisterButton (
                   SCT.LOCALS.SCT_CB_NAME,
                   SCT.LOCALS.SCT_CB_SHORT_DESC,
                   SCT.LOCALS.SCT_CB_LONG_DESC,
                   SCT.LOCALS.SCT_CB_ICON,
                   SCT.ShowMenu,
                   function()
                      return true;
                   end
                );
                default_config.ENABLED = 0;
        end

        -- Add to CTMod Control panel if available
        if ( CT_RegisterMod ) then
                CT_RegisterMod(SCT.LOCALS.CB_NAME, nil, 5, SCT.LOCALS.CB_ICON, SCT.LOCALS.CB_LONG_DESC, "switch", nil, SCT.ShowMenu);
        end
        
end

-------------------------
--Get the default Config
function SCT:GetDefaultConfig()
        local default = {
                ["VERSION"] = SCT.Version,
                ["ENABLED"] = true,
                ["SHOWHIT"] = 1,
                ["SHOWMISS"] = 1,
                ["SHOWDODGE"] = 1,
                ["SHOWPARRY"] = 1,
                ["SHOWBLOCK"] = 1,
                ["SHOWSPELL"] = 1,
                ["SHOWHEAL"] = 1,
                ["SHOWRESIST"] = 1,
                ["SHOWDEBUFF"] = 1,
                ["SHOWBUFF"] = 1,
                ["SHOWFADE"] = false,
                ["SHOWABSORB"] = 1,
                ["SHOWLOWHP"] = 1,
                ["SHOWLOWMANA"] = 1,
                ["SHOWPOWER"] = 1,
                ["SHOWCOMBAT"] = false,
                ["SHOWCOMBOPOINTS"] = false,
                ["SHOWHONOR"] = 1,
                ["SHOWEXECUTE"] = 1,
                ["SHOWREP"] = 1,
                ["SHOWSELFHEAL"] = 1,
                ["SHOWSKILL"] = 1,
                ["SHOWTARGETS"] = 1,
                ["SHOWSELF"] = false,
                ["SHOWOVERHEAL"] = 1,
                ["STICKYCRIT"] = 1,
                ["FLASHCRIT"] = 1,
                ["SPELLTYPE"] = false,
                ["SPELLCOLOR"] = false,
                ["DMGFONT"] = false,
                ["SHOWALLPOWER"] = false,
                ["FPSMODE"] = false,
                ["ANIMATIONSPEED"] = 15,
                ["MOVEMENT"] = 2,
                ["LOWHP"] = 40,
                ["LOWMANA"] = 40,
                ["HEALFILTER"] = 50,
                ["PLAYSOUND"] = 1,
                ["CUSTOMEVENTS"] = 1,
                ["LIGHTMODE"] = false,
                [SCT.FRAMES_DATA_TABLE] = {
                        [SCT.FRAME1] = {
                                ["FONT"] = 1,
                                ["FONTSHADOW"] = 2,
                                ["ALPHA"] = 100,
                                ["ANITYPE"] = 1,
                                ["ANISIDETYPE"] = 1,
                                ["XOFFSET"] = 0,
                                ["YOFFSET"] = 0,
                                ["DIRECTION"] = false,
                                ["TEXTSIZE"] = 24,
                        },
                        [SCT.FRAME2] = {
                                ["FONT"] = 1,
                                ["FONTSHADOW"] = 2,
                                ["ALPHA"] = 100,
                                ["ANITYPE"] = 1,
                                ["ANISIDETYPE"] = 1,
                                ["XOFFSET"] = 0,
                                ["YOFFSET"] = -150,
                                ["DIRECTION"] = true,
                                ["TEXTSIZE"] = 24,
                        },
                        [SCT.MSG] = {
                                ["MSGFADE"] = 1.5,
                                ["MSGFONT"] = 1,
                                ["MSGFONTSHADOW"] = 2,
                                ["MSGSIZE"] = 24,
                                ["MSGYOFFSET"] = -280,
                                ["MSGXOFFSET"] = 0,
                        }
                },
                [SCT.COLORS_TABLE] = {
                        ["SHOWHIT"] =  {r = 1.0, g = 0.0, b = 0.0},
                        ["SHOWMISS"] =  {r = 0.0, g = 0.0, b = 1.0},
                        ["SHOWDODGE"] =  {r = 0.0, g = 0.0, b = 1.0},
                        ["SHOWPARRY"] =  {r = 0.0, g = 0.0, b = 1.0},
                        ["SHOWBLOCK"] =  {r = 0.0, g = 0.0, b = 1.0},
                        ["SHOWSPELL"] =  {r = 0.5, g = 0.0, b = 0.5},
                        ["SHOWHEAL"] =  {r = 0.0, g = 1.0, b = 0.0},
                        ["SHOWRESIST"] =  {r = 0.5, g = 0.0, b = 0.5},
                        ["SHOWDEBUFF"] =  {r = 0.0, g = 0.5, b = 0.5},
                        ["SHOWABSORB"] =  {r = 1.0, g = 1.0, b = 0.0},
                        ["SHOWLOWHP"] =  {r = 1.0, g = 0.5, b = 0.5},
                        ["SHOWLOWMANA"] =  {r = 0.5, g = 0.5, b = 1.0},
                        ["SHOWPOWER"] =  {r = 1.0, g = 1.0, b = 0.0},
                        ["SHOWCOMBAT"] =  {r = 1.0, g = 1.0, b = 1.0},
                        ["SHOWCOMBOPOINTS"] =  {r = 1.0, g = 0.5, b = 0.0},
                        ["SHOWHONOR"] =  {r = 0.5, g = 0.5, b = 0.7},
                        ["SHOWBUFF"] =  {r = 0.7, g = 0.7, b = 0.0},
                        ["SHOWFADE"] =  {r = 0.7, g = 0.7, b = 0.0},
                        ["SHOWEXECUTE"] =  {r = 0.7, g = 0.7, b = 0.7},
                        ["SHOWREP"] =  {r = 0.5, g = 0.5, b = 1},
                        ["SHOWSELFHEAL"] = {r = 0, g = 0.7, b = 0},
                        ["SHOWSKILL"] = {r = 0, g = 0, b = 0.7}
                },
                [SCT.CRITS_TABLE] = {
                        ["SHOWEXECUTE"] = 1,
                        ["SHOWLOWHP"] = 1,
                        ["SHOWLOWMANA"] = 1,
                },
                [SCT.FRAMES_TABLE] = {
                        ["SHOWHIT"] = SCT.FRAME1,
                        ["SHOWMISS"] = SCT.FRAME1,
                        ["SHOWDODGE"] = SCT.FRAME1,
                        ["SHOWPARRY"] = SCT.FRAME1,
                        ["SHOWBLOCK"] = SCT.FRAME1,
                        ["SHOWSPELL"] = SCT.FRAME1,
                        ["SHOWHEAL"] = SCT.FRAME2,
                        ["SHOWRESIST"] = SCT.FRAME1,
                        ["SHOWDEBUFF"] = SCT.FRAME1,
                        ["SHOWABSORB"] = SCT.FRAME1,
                        ["SHOWLOWHP"] = SCT.FRAME1,
                        ["SHOWLOWMANA"] = SCT.FRAME1,
                        ["SHOWPOWER"] = SCT.FRAME2,
                        ["SHOWCOMBAT"] = SCT.FRAME2,
                        ["SHOWCOMBOPOINTS"] = SCT.FRAME1,
                        ["SHOWHONOR"] = SCT.MSG,
                        ["SHOWBUFF"] = SCT.MSG,
                        ["SHOWFADE"] = SCT.FRAME1,
                        ["SHOWEXECUTE"] = SCT.FRAME1,
                        ["SHOWREP"] = SCT.MSG,
                        ["SHOWSELFHEAL"] = SCT.FRAME2   ,
                        ["SHOWSKILL"] = SCT.FRAME2
                }
        };
        return default;
end

-------------------------
--Regsiter SCT with all events
function SCT:RegisterSelfEvents()

        -- Register Main Events
        self:RegisterEvent("UNIT_HEALTH", "OnEvent");
        self:RegisterEvent("UNIT_MANA", "OnEvent");
        self:RegisterEvent("UNIT_ENERGY", "OnEvent");
        self:RegisterEvent("UNIT_RAGE", "OnEvent");
        self:RegisterEvent("UNIT_DISPLAYPOWER", "OnEvent");
        self:RegisterEvent("PLAYER_REGEN_ENABLED", "OnEvent");
        self:RegisterEvent("PLAYER_REGEN_DISABLED", "OnEvent");
        self:RegisterEvent("PLAYER_COMBO_POINTS", "OnEvent");
        self:RegisterEvent("COMBAT_TEXT_UPDATE", "BlizzardCombatTextEvent");
        
        --unsupported chat events:
        self:RegisterEvent("CHAT_MSG_SKILL", "OnEvent");
        
        --events need for light and normal mode for Parserlib
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_SELF_BUFF", SCT.ParseCombat) ;
        
        --if in light mode, end here
        if (self.db.profile["LIGHTMODE"]) then
                return;
        end
        
        --events only needed in normal mode for Parserlib
        parser:RegisterEvent("sct", "CHAT_MSG_COMBAT_SELF_HITS", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_SELF_DAMAGE", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF", SCT.ParseCombat) ;
  parser:RegisterEvent("sct", "CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS", SCT.ParseCombat) ;
        parser:RegisterEvent("sct", "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS", SCT.ParseCombat) ;
        
        --searchable added events
        local key, value
        for key, value in SCT.EventList do
                self:RegisterEvent(value, "OnEvent");
        end
end

------------------------------
---Sort a table by its keys.
---stolen from http://www.lua.org/pil/19.3.html
function SCT:PairsByKeys (t, f)
  local a = {}
  for n in pairs(t) do table.insert(a, n) end
  table.sort(a, f)
  local i = 0      -- iterator variable
  local iter = function ()   -- iterator function
    i = i + 1
    if a[i] == nil then return nil
    else return a[i], t[a[i]]
    end
  end
  return iter
end

------------------------------
--Create event to load up correct font
--when another mod loads. Incase they try to change
--the font (super inspect, etc...)
SCT:RegisterEvent("ADDON_LOADED", SCT.SetDmgFont);