CCWatchDetails = { name = "CCWatch", version = CWATCH_VERSION, releaseDate = "March 27, 2006", author = "phoenixfire2001&elwen", website = "http://www.curse-gaming.com/mod.php?addid=3650", category = MYADDONS_CATEGORY_COMBAT, description = CCWATCH_DESCRIPTION, optionsframe = "CCWatchOptionsFrame" }; CCWatchHelp = { "/ccw : affiche les commandes possibles\n".. "/ccw config : affiche l'interface graphique\n".. "\n".. "" } --CCWATCH_INITIALIZATION_EVENT = "SPELL_CHANGED" CCWatchLoaded = false; CCWatchObject = nil; CCWATCH_MAXBARS = 5; CCW_EWARN_FADED = 1; CCW_EWARN_APPLIED = 2; CCW_EWARN_BROKEN = 4; CCW_EWARN_LOWTIME = 8; --[[ local function DebugCompareStrings(str1, str2) local str = ""; if str1 == str2 then test = str1.." == "..str2; else local str = ""; local len = string.len(str1); if len > string.len(str2) then len = string.len(str2); end local i; for i=1,len do s1char = string.sub(str1, i, i); s2char = string.sub(str1, i, i); str = i.." : "..s1char.." ["..string.byte(s1char) .."] -> "..s2char.." ["..string.byte(s2char).."]"; if s1char ~= s2char then str = str.." => DIFFERENT"; end CCWatch_AddMessage(str); end end end --]] function CCWatchWarn(msg, effect, target, time) local ncc = 0; local cc = CCWATCH.WARNTYPE; -- Emote, Say, Party, Raid, Yell, Custom: if cc == "RAID" and UnitInRaid("player") == nil then cc = "PARTY"; end if cc == "PARTY" and GetNumPartyMembers() == 0 then return; end if cc == "CHANNEL" then ncc = GetChannelName(CCWATCH.WARNCUSTOMCC); end if time ~= nil then msg = format(msg, target, effect, time); else msg = format(msg, target, effect); end if cc == "EMOTE" then msg = CCWATCH_WARN_EMOTE..msg; end SendChatMessage(msg, cc, nil, ncc); end function CCWatch_Config() CCWATCH.CCS = {} if CCWatch_ConfigCC ~= nil then CCWatch_ConfigCC(); else CCWatch_AddMessage("No CC config"); end if CCWatch_ConfigDebuff ~= nil then CCWatch_ConfigDebuff(); else CCWatch_AddMessage("No Debuff config"); end if CCWatch_ConfigBuff ~= nil then CCWatch_ConfigBuff(); else CCWatch_AddMessage("No Buff config"); end end function CCWatch_OnLoad() CCWatch_Globals(); CCWatch_Config(); CCWatchObject = this; -- this:RegisterEvent(CCWATCH_INITIALIZATION_EVENT); this:RegisterEvent("UNIT_AURA"); this:RegisterEvent("UNIT_COMBAT"); if UnitLevel("player") < 60 then this:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN"); -- TODO : add this -- this:RegisterEvent("CHAT_MSG_COMBAT_HONOR_GAIN"); end -- register this also for < 60 (pvp) this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILE_DEATH"); this:RegisterEvent("CHAT_MSG_SPELL_AURA_GONE_OTHER"); this:RegisterEvent("CHAT_MSG_SPELL_BREAK_AURA"); this:RegisterEvent("SPELLCAST_START"); this:RegisterEvent("SPELLCAST_STOP"); this:RegisterEvent("SPELLCAST_FAILED"); this:RegisterEvent("SPELLCAST_INTERRUPTED"); this:RegisterEvent("PLAYER_TARGET_CHANGED"); SLASH_CCWATCH1 = "/ccwatch"; SLASH_CCWATCH2 = "/ccw"; SlashCmdList["CCWATCH"] = function(msg) CCWatch_SlashCommandHandler(msg); end CCWatch_AddMessage(CCWATCH_FULLVERSION..CCWATCH_LOADED); end function CCWatch_BarUnlock() CCWATCH.STATUS = 2; CCWatchCC:EnableMouse(1); CCWatchDebuff:EnableMouse(1); CCWatchBuff:EnableMouse(1); local i; for i=1,CCWATCH_MAXBARS do getglobal("CCWatchBarCC"..i):Show(); getglobal("CCWatchBarDebuff"..i):Show(); getglobal("CCWatchBarBuff"..i):Show(); end end function CCWatch_BarLock() CCWATCH.STATUS = 1; CCWatchCC:EnableMouse(0); CCWatchDebuff:EnableMouse(0); CCWatchBuff:EnableMouse(0); local i; for i=1,CCWATCH_MAXBARS do getglobal("CCWatchBarCC"..i):Hide(); getglobal("CCWatchBarDebuff"..i):Hide(); getglobal("CCWatchBarBuff"..i):Hide(); end end function CCWatch_SlashCommandHandler(msg) if( msg ) then local command = string.lower(msg); if( command == "on" ) then if( CCWATCH.STATUS == 0 ) then CCWATCH.STATUS = 1; CCWatch_Save[CCWATCH.PROFILE].status = CCWATCH.STATUS; CCWatch_AddMessage(CCWATCH_ENABLED); end elseif( command == "off" ) then if( CCWATCH.STATUS ~= 0 ) then CCWATCH.STATUS = 0; CCWatch_Save[CCWATCH.PROFILE].status = CCWATCH.STATUS; CCWatch_AddMessage(CCWATCH_DISABLED); end elseif( command == "unlock" ) then CCWatch_BarUnlock(); CCWatch_AddMessage(CCWATCH_UNLOCKED); CCWatchOptionsFrameUnlock:SetChecked(true); elseif( command == "lock" ) then CCWatch_BarLock(); CCWatch_AddMessage(CCWATCH_LOCKED); CCWatchOptionsFrameUnlock:SetChecked(false); elseif( command == "invert" ) then CCWATCH.INVERT = not CCWATCH.INVERT; CCWatch_Save[CCWATCH.PROFILE].invert = CCWATCH.INVERT; if CCWATCH.INVERT then CCWatch_AddMessage(CCWATCH_INVERSION_ON); else CCWatch_AddMessage(CCWATCH_INVERSION_OFF); end CCWatchOptionsFrameInvert:SetChecked(CCWATCH.INVERT); elseif( command == "timers off" ) then CCWatch_Save[CCWATCH.PROFILE].timers = 0; CCWATCH.TIMERS = CCWatch_Save[CCWATCH.PROFILE].timers; CCWatch_AddMessage(CCWATCH_TIMERS_OFF) CCWatchTimersDropDownText:SetText(CCWATCH_OPTION_TIMERS_OFF); elseif( command == "timers on" ) then CCWatch_Save[CCWATCH.PROFILE].timers = 1; CCWATCH.TIMERS = CCWatch_Save[CCWATCH.PROFILE].timers; CCWatch_AddMessage(CCWATCH_TIMERS_ON) CCWatchTimersDropDownText:SetText(CCWATCH_OPTION_TIMERS_ON); elseif( command == "timers rev" ) then CCWatch_Save[CCWATCH.PROFILE].timers = 2; CCWATCH.TIMERS = CCWatch_Save[CCWATCH.PROFILE].timers; CCWatch_AddMessage(CCWATCH_TIMERS_REVERSE) CCWatchTimersDropDownText:SetText(CCWATCH_OPTION_TIMERS_REVERSE); elseif( command == "grow off" ) then CCWatch_Save[CCWATCH.PROFILE].growth = 0; CCWATCH.GROWTH = CCWatch_Save[CCWATCH.PROFILE].growth; CCWatch_AddMessage(CCWATCH_GROW_OFF) CCWatchGrowthDropDownText:SetText(CCWATCH_OPTION_GROWTH_OFF); elseif( command == "grow up" ) then CCWatch_Save[CCWATCH.PROFILE].growth = 1; CCWATCH.GROWTH = CCWatch_Save[CCWATCH.PROFILE].growth; CCWatch_AddMessage(CCWATCH_GROW_UP) CCWatchGrowthDropDownText:SetText(CCWATCH_OPTION_GROWTH_UP); elseif( command == "grow down" ) then CCWatch_Save[CCWATCH.PROFILE].growth = 2; CCWATCH.GROWTH = CCWatch_Save[CCWATCH.PROFILE].growth; CCWatch_AddMessage(CCWATCH_GROW_DOWN) CCWatchGrowthDropDownText:SetText(CCWATCH_OPTION_GROWTH_DOWN); elseif( command == "clear" ) then CCWatch_Save[CCWATCH.PROFILE] = nil; CCWatch_Globals(); CCWatch_Config(); CCWatch_LoadVariables(); elseif( command == "u" ) then CCWatch_Config(); CCWatch_LoadConfCCs(); CCWatch_LoadCustomCCs(); CCWatch_UpdateClassSpells(true); elseif( command == "config" ) then CCWatchOptionsFrame:Show(); elseif( string.sub(command, 1, 5) == "scale" ) then local scale = tonumber(string.sub(command, 7)) if( scale <= 3.0 and scale >= 0.25 ) then CCWatch_Save[CCWATCH.PROFILE].scale = scale; CCWATCH.SCALE = scale; CCWatchCC:SetScale(CCWATCH.SCALE); CCWatchDebuff:SetScale(CCWATCH.SCALE); CCWatchBuff:SetScale(CCWATCH.SCALE); CCWatch_AddMessage(CCWATCH_SCALE..scale); CCWatchSliderScale:SetValue(CCWATCH.SCALE); else CCWatch_Help() end elseif( string.sub(command, 1, 5) == "width" ) then local width = tonumber(string.sub(command, 7)) if( width <= 300 and width >= 50 ) then CCWatch_Save[CCWATCH.PROFILE].width = width; CCWATCH.WIDTH = width; CCWatch_SetWidth(CCWATCH.WIDTH); CCWatch_AddMessage(CCWATCH_WIDTH..width); CCWatchSliderWidth:SetValue(CCWATCH.WIDTH); else CCWatch_Help() end elseif( string.sub(command, 1, 5) == "alpha" ) then local alpha = tonumber(string.sub(command, 7)) if( alpha <= 1 and alpha >= 0 ) then CCWatch_Save[CCWATCH.PROFILE].alpha = alpha; CCWATCH.ALPHA = alpha; CCWatch_AddMessage(CCWATCH_ALPHA..alpha); CCWatchSliderAlpha:SetValue(CCWATCH.ALPHA); else CCWatch_Help() end elseif( command == "print" ) then CCWatch_AddMessage(CCWATCH_PROFILE_TEXT..CCWATCH.PROFILE); if( CCWATCH.STATUS == 0 ) then CCWatch_AddMessage(CCWATCH_DISABLED); elseif( CCWATCH.STATUS == 2 ) then CCWatch_AddMessage(CCWATCH_UNLOCKED); else CCWatch_AddMessage(CCWATCH_ENABLED); end if CCWATCH.INVERT then CCWatch_AddMessage(CCWATCH_INVERSION_ON); else CCWatch_AddMessage(CCWATCH_INVERSION_OFF); end if CCWATCH.TIMERS == 0 then CCWatch_AddMessage(CCWATCH_TIMERS_OFF); elseif CCWATCH.TIMERS == 1 then CCWatch_AddMessage(CCWATCH_TIMERS_ON); else CCWatch_AddMessage(CCWATCH_TIMERS_REVERSE); end if CCWATCH.GROWTH == 0 then CCWatch_AddMessage(CCWATCH_GROW_OFF); elseif CCWATCH.GROWTH == 1 then CCWatch_AddMessage(CCWATCH_GROW_UP); else CCWatch_AddMessage(CCWATCH_GROW_DOWN); end CCWatch_Config(); CCWatch_LoadConfCCs(); CCWatch_LoadCustomCCs(); CCWatch_UpdateClassSpells(true); -- Update at the same time CCWatch_AddMessage(CCWATCH_SCALE..CCWATCH.SCALE); CCWatch_AddMessage(CCWATCH_WIDTH..CCWATCH.WIDTH); CCWatch_AddMessage(CCWATCH_ALPHA..CCWATCH.ALPHA); elseif( string.sub(command, 1, 6) == "warncc" ) then local cc = string.sub(command, 8); if cc ~= "EMOTE" or cc ~= "SAY" or cc ~= "PARTY" or cc ~= "RAID" or cc ~= "YELL" or cc ~= "CHANNEL" then CCWatch_Save[CCWATCH.PROFILE].WarnCustomCC = cc; CCWATCH.WARNCUSTOMCC = cc; CCWatch_Save[CCWATCH.PROFILE].WarnType = "CHANNEL"; CCWatch_AddMessage(CCWATCH_WARNCC_CUSTOM..cc); else CCWatch_Save[CCWATCH.PROFILE].WarnType = cc; CCWatch_AddMessage(CCWATCH_WARNCC_SETTO..cc); end CCWATCH.WARNTYPE = CCWatch_Save[CCWATCH.PROFILE].WarnType; elseif( command == "warn" ) then if CCWATCH.WARNMSG then CCWATCH.WARNMSG = 0; CCWatch_AddMessage(CCWATCH_WARN_DISABLED); else CCWATCH.WARNMSG = bit.bor(CCW_EWARN_FADED, CCW_EWARN_APPLIED, CCW_EWARN_BROKEN, CCW_EWARN_LOWTIME); CCWatch_AddMessage(CCWATCH_WARN_ENABLED); UpdateWarnUIPage(); end CCWatch_Save[CCWATCH.PROFILE].WarnMsg = CCWATCH.WARNMSG; else CCWatch_Help(); end end end function CCWatch_OnEvent(event) -- if ( CCWATCH.STATUS == 0 and event ~= CCWATCH_INITIALIZATION_EVENT ) then if ( CCWATCH.STATUS == 0 ) then return end CCWatch_EventHandler[event](arg1, arg2, arg3, arg4, arg5); end CCWatch_EventHandler = {} local SpellCast = nil; --CCWatch_EventHandler[CCWATCH_INITIALIZATION_EVENT] = function() -- if not CCWatchObject then -- if(myAddOnsFrame_Register) then -- myAddOnsFrame_Register(CCWatchDetails, CCWatchHelp); -- end -- CCWatch_LoadVariables(); -- end --end CCWatch_EventHandler["SPELLCAST_START"] = function() SpellCast = arg1; -- duration = arg2; -- might wanna play with it to deduce the used rank end CCWatch_EventHandler["SPELLCAST_STOP"] = function() local effect; effect = SpellCast; local target = UnitName("target"); if effect ~= nil and target ~= nil then if CCWATCH.CCS[effect] then local group = CCWATCH.CCS[effect].GROUP; local etype = CCWATCH.CCS[effect].ETYPE; local index = 0; -- find the effect in the queue, if it's not there index stays 0 if etype == ETYPE_BUFF then table.foreach( CCWATCH.GROUPSBUFF[group].EFFECT, function(k,v) if( v == effect ) then index = k end end ); elseif etype == ETYPE_DEBUFF then table.foreach( CCWATCH.GROUPSDEBUFF[group].EFFECT, function(k,v) if( v == effect ) then index = k end end ); else table.foreach( CCWATCH.GROUPSCC[group].EFFECT, function(k,v) if( v == effect ) then index = k end end ); end if( index ~= 0 ) then -- Found the effect in a group, hence it is active, hence we are resetting it CCWATCH.UNIT_AURA.TIME = GetTime(); CCWATCH.UNIT_AURA.TARGET = target; CCWATCH.CCS[effect].TARGET = target; local diff = CCWATCH.UNIT_AURA.TIME - CCWATCH.CCS[effect].TIMER_START; CCWATCH.CCS[effect].TIMER_START = CCWATCH.CCS[effect].TIMER_START + diff; CCWATCH.CCS[effect].TIMER_END = CCWATCH.CCS[effect].TIMER_END + diff; end end end SpellCast = nil; end CCWatch_EventHandler["SPELLCAST_FAILED"] = function() SpellCast = nil; end CCWatch_EventHandler["SPELLCAST_INTERRUPTED"] = function() SpellCast = nil; end CCWatch_EventHandler["UNIT_AURA"] = function() if( arg1 == "target") then CCWATCH.UNIT_AURA.TARGET = UnitName("target"); CCWATCH.UNIT_AURA.TIME = GetTime(); -- get rid of any old events so they don't clutter the queue while table.getn(CCWATCH.EFFECT) > 0 and (CCWATCH.UNIT_AURA.TIME - CCWATCH.EFFECT[1].TIME) > CCWATCH.THRESHOLD do CCWatch_UnqueueEvent(); end if table.getn(CCWATCH.EFFECT) > 0 then CCWatch_EffectHandler[CCWATCH.EFFECT[1].STATUS](); end end end CCWatch_EventHandler["PLAYER_TARGET_CHANGED"] = function() if not UnitCanAttack("player", "target") then return; end local index = 0; local target = UnitName("target"); -- 1. Check if current target is present in the list table.foreach( CCWATCH.LASTTARGETS, function(k,v) if( v.TARGET == target ) then index = k end end ); local ltime = GetTime(); if index == 0 then -- 2. add it CCWatch_AddLastTarget(target, ltime); else -- or update target time effect CCWATCH.LASTTARGETS[index].TIME = ltime; end end CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"] = function() local mobname; local effect; for mobname, effect in string.gfind( arg1, CCWATCH_TEXT_ON ) do if( CCWATCH.STYLE > 1 or CCWatch_CheckRecentTargets(mobname) ) then if CCWATCH.CCS[effect] and CCWATCH.CCS[effect].MONITOR and bit.band(CCWATCH.CCS[effect].ETYPE, CCWATCH.MONITORING) ~= 0 then CCWatch_QueueEvent(effect, mobname, GetTime(), 1) CCWatch_EffectHandler[1](); end end end end CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS"] = function() local mobname; local effect; for mobname, effect in string.gfind( arg1, CCWATCH_TEXT_BUFF_ON ) do if( CCWATCH.STYLE > 1 or CCWatch_CheckRecentTargets(mobname) ) then if CCWATCH.CCS[effect] and CCWATCH.CCS[effect].MONITOR and bit.band(CCWATCH.CCS[effect].ETYPE, CCWATCH.MONITORING) ~=0 then CCWatch_QueueEvent(effect, mobname, GetTime(), 1) CCWatch_EffectHandler[1](); end end end end CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"] = CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS"]; CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"] = CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"]; CCWatch_EventHandler["CHAT_MSG_SPELL_AURA_GONE_OTHER"] = function() local mobname; local effect; for effect, mobname in string.gfind( arg1, CCWATCH_TEXT_OFF ) do if CCWATCH.CCS[effect] then if( CCWATCH.CCS[effect].TARGET == mobname ) then CCWatch_QueueEvent(effect, mobname, GetTime(), 2) CCWatch_EffectHandler[2](); end end end end CCWatch_EventHandler["CHAT_MSG_SPELL_BREAK_AURA"] = function() local mobname; local effect; for mobname, effect in string.gfind( arg1, CCWATCH_TEXT_BREAK ) do if( CCWATCH.CCS[effect] ) then if( CCWATCH.CCS[effect].TARGET == mobname ) then CCWatch_QueueEvent(effect, mobname, GetTime(), 3) CCWatch_EffectHandler[3](); end end end end local DeadMob = ""; local function CCWHandleTargetDeath(k, v) if( v ) then if( v.TARGET == DeadMob ) then --CCWatch_AddMessage("Removing effect "..k); CCWATCH.CCS[k].TIMER_END = GetTime(); CCWatch_RemoveEffect(k, false); end end end CCWatch_EventHandler["CHAT_MSG_COMBAT_HOSTILE_DEATH"] = function() local mobname; for mobname in string.gfind( arg1, CCWATCH_TEXT_DIE ) do -- for each effect (arg oO) check if target is current DeadMob = mobname; table.foreach(CCWATCH.CCS, CCWHandleTargetDeath); end end CCWatch_EventHandler["CHAT_MSG_COMBAT_XP_GAIN"] = function() local mobname; for mobname in string.gfind( arg1, CCWATCH_TEXT_DIEXP ) do -- for each effect (arg oO) check if target is current DeadMob = mobname; table.foreach(CCWATCH.CCS, CCWHandleTargetDeath); end end CCWatch_EventHandler["UNIT_COMBAT"] = function() if( GetComboPoints() > 0 ) then CCWATCH.COMBO = GetComboPoints(); end end CCWatch_EffectHandler = {} CCWatch_EffectHandler[0] = function() -- no effect end CCWatch_EffectHandler[1] = function() -- applied if( CCWATCH.STYLE ~= 0 or math.abs( CCWATCH.UNIT_AURA.TIME - CCWATCH.EFFECT[1].TIME ) < CCWATCH.THRESHOLD ) then local effect = CCWATCH.EFFECT[1].TYPE; local mobname = CCWATCH.EFFECT[1].TARGET; if( GetTime() > ( CCWATCH.CCS[effect].TIMER_END + 15 ) or mobname ~= CCWATCH.CCS[effect].TARGET ) then -- quick & dirty hack for shared DR between Seduce & Fear) if( effect == CCWATCH_FEAR or effect == CCWATCH_SEDUCE ) then CCWATCH.CCS[CCWATCH_FEAR].DIMINISH = 1; CCWATCH.CCS[CCWATCH_SEDUCE].DIMINISH = 1; else CCWATCH.CCS[effect].DIMINISH = 1; end end CCWATCH.CCS[effect].TARGET = mobname; CCWATCH.CCS[effect].PLAYER = UnitIsPlayer("target"); CCWATCH.CCS[effect].TIMER_START = GetTime(); if( CCWATCH.CCS[effect].PVPCC and CCWATCH.CCS[effect].PLAYER ) then CCWATCH.CCS[effect].TIMER_END = CCWATCH.CCS[effect].TIMER_START + (CCWATCH.CCS[effect].PVPCC / CCWATCH.CCS[effect].DIMINISH); else CCWATCH.CCS[effect].TIMER_END = CCWATCH.CCS[effect].TIMER_START + (CCWATCH.CCS[effect].LENGTH / CCWATCH.CCS[effect].DIMINISH); end if( CCWATCH.CCS[effect].COMBO ) then CCWATCH.CCS[effect].TIMER_END = CCWATCH.CCS[effect].TIMER_END + CCWATCH.CCS[effect].A * CCWATCH.COMBO; end CCWatch_AddEffect(effect); CCWatch_UnqueueEvent(); if CCWATCH.CCS[effect].WARN > 0 and bit.band(CCWATCH.WARNMSG, CCW_EWARN_APPLIED) then CCWatchWarn(CCWATCH_WARN_APPLIED, effect, mobname); end end end CCWatch_EffectHandler[2] = function() -- faded local effect = CCWATCH.EFFECT[1].TYPE; local target = CCWATCH.CCS[effect].TARGET; local bUnqueueDone = false; if( target == CCWATCH.EFFECT[1].TARGET ) then -- target and CC target names match, wait for UNIT_AURA to ensure target match if( CCWATCH.STYLE ~= 0 or math.abs( CCWATCH.UNIT_AURA.TIME - CCWATCH.EFFECT[1].TIME ) < CCWATCH.THRESHOLD ) then CCWATCH.CCS[effect].TIMER_END = GetTime(); CCWatch_RemoveEffect(effect, false); CCWatch_UnqueueEvent(); bUnqueueDone = true; -- unless the debuff is gone from the target, then no need for UNIT_AURA to confirm it elseif CCWATCH.STYLE == 0 and CCWatch_EffectGone(effect) then CCWATCH.CCS[effect].TIMER_END = GetTime() CCWatch_RemoveEffect(effect, false); CCWatch_UnqueueEvent(); bUnqueueDone = true; end else -- target and CC target names don't match, retargetting has occured, no need to wait for UNIT_AuRA CCWATCH.CCS[effect].TIMER_END = GetTime(); CCWatch_RemoveEffect(effect, false); CCWatch_UnqueueEvent(); bUnqueueDone = true; end -- another hack, to avoid spamming, because when the effect is broken, SOMETIME, WoW also send a faded message (see combat log) if bUnqueueDone and CCWATCH.CCS[effect].WARN > 0 and CCWATCH.CCS[effect].WARN ~= 3 and bit.band(CCWATCH.WARNMSG, CCW_EWARN_FADED) then CCWatchWarn(CCWATCH_WARN_FADED, effect, target); end end CCWatch_EffectHandler[3] = function() -- broken local effect = CCWATCH.EFFECT[1].TYPE; local target = CCWATCH.CCS[effect].TARGET; local bUnqueueDone = false; if( target == CCWATCH.EFFECT[1].TARGET ) then -- target and CC target names match, wait for UNIT_AURA to ensure target match if( CCWATCH.STYLE ~= 0 or math.abs( CCWATCH.UNIT_AURA.TIME - CCWATCH.EFFECT[1].TIME ) < CCWATCH.THRESHOLD ) then CCWATCH.CCS[effect].TIMER_END = GetTime(); CCWatch_RemoveEffect(effect, false); CCWatch_UnqueueEvent(); bUnqueueDone = true; -- unless the debuff is gone from the target, then no need for UNIT_AURA to confirm it elseif CCWATCH.STYLE == 0 and CCWatch_EffectGone(effect) then CCWATCH.CCS[effect].TIMER_END = GetTime() CCWatch_RemoveEffect(effect, false); CCWatch_UnqueueEvent(); bUnqueueDone = true; end else -- target and CC target names don't match, retargetting has occured, no need to wait for UNIT_AuRA CCWATCH.CCS[effect].TIMER_END = GetTime(); CCWatch_RemoveEffect(effect, false); CCWatch_UnqueueEvent(); bUnqueueDone = true; end if bUnqueueDone and CCWATCH.CCS[effect].WARN > 0 and bit.band(CCWATCH.WARNMSG, CCW_EWARN_BROKEN) then CCWatchWarn(CCWATCH_WARN_BROKEN, effect, target); CCWATCH.CCS[effect].WARN = 3; end end function CCWatch_QueueEvent(effect, mobname, time, status) local effect_structure = {} effect_structure.TYPE = effect; effect_structure.TARGET = mobname; effect_structure.TIME = time; effect_structure.STATUS = status table.insert( CCWATCH.EFFECT, effect_structure ) end function CCWatch_UnqueueEvent() table.remove( CCWATCH.EFFECT, 1) end function CCWatch_EffectGone(effect) local i; local effectgone = false; -- assume effect is gone unless we find it for i = 1,16 do if UnitDebuff("target", i) == CCWATCH.CCS[effect].TEXTURE then effectgone = true end end return effectgone; end function CCWatch_AddEffect(effect) -- first remove any old copies of this effect, to avoid nasty overlap and properly set diminishing returns for multi-CC local group = CCWATCH.CCS[effect].group local GROUPS; CCWatch_RemoveEffect(effect, true) if CCWATCH.CCS[effect].ETYPE == ETYPE_BUFF then GROUPS = CCWATCH.GROUPSBUFF; elseif CCWATCH.CCS[effect].ETYPE == ETYPE_DEBUFF then GROUPS = CCWATCH.GROUPSDEBUFF; else GROUPS = CCWATCH.GROUPSCC; end if CCWATCH.GROWTH == 1 then group = 1 -- start at the bottom and find the first available bar, otherwise queue to #CCWATCH_MAXBARS while group < CCWATCH_MAXBARS and table.getn(GROUPS[group].EFFECT) > 0 do group = group + 1 end CCWATCH.CCS[effect].GROUP = group elseif CCWATCH.GROWTH == 2 then group = CCWATCH_MAXBARS -- start at the top and find the first available bar, otherwise queue to #1 while group > 1 and table.getn(GROUPS[group].EFFECT) > 0 do group = group - 1 end CCWATCH.CCS[effect].GROUP = group end -- new effect goes at the head of the queue... always displaying newest effect CCWatch_QueueEffect(effect) end function CCWatch_RemoveEffect(effect, dr) local group = CCWATCH.CCS[effect].GROUP; local GROUPS; CCWatch_UnqueueEffect(effect); if CCWATCH.CCS[effect].ETYPE == ETYPE_BUFF then GROUPS = CCWATCH.GROUPSBUFF; elseif CCWATCH.CCS[effect].ETYPE == ETYPE_DEBUFF then GROUPS = CCWATCH.GROUPSDEBUFF; else GROUPS = CCWATCH.GROUPSCC; end if CCWATCH.GROWTH == 1 then while group < CCWATCH_MAXBARS and table.getn(GROUPS[group].EFFECT) == 0 and table.getn(GROUPS[group+1].EFFECT) > 0 do local move_effect = GROUPS[group+1].EFFECT[1]; CCWatch_UnqueueEffect(move_effect); CCWATCH.CCS[move_effect].GROUP = group CCWatch_QueueEffect(move_effect); group = group + 1 end elseif CCWATCH.GROWTH == 2 then while group > 1 and table.getn(GROUPS[group].EFFECT) == 0 and table.getn(GROUPS[group-1].EFFECT) > 0 do local move_effect = GROUPS[group-1].EFFECT[1]; CCWatch_UnqueueEffect(move_effect); CCWATCH.CCS[move_effect].GROUP = group CCWatch_QueueEffect(move_effect); group = group - 1 end end -- set diminishing returns based on CCS[effect].DIMINISHES (documented in CCWatch_ConfigXX.lua) if( dr and ((CCWATCH.CCS[effect].PLAYER and CCWATCH.CCS[effect].DIMINISHES > 0) or CCWATCH.CCS[effect].DIMINISHES == 1) ) then -- quick & dirty hack for shared DR between Seduce & Fear) if( effect == CCWATCH_FEAR or effect == CCWATCH_SEDUCE ) then CCWATCH.CCS[CCWATCH_FEAR].DIMINISH = 2 * CCWATCH.CCS[CCWATCH_FEAR].DIMINISH; CCWATCH.CCS[CCWATCH_SEDUCE].DIMINISH = 2 * CCWATCH.CCS[CCWATCH_SEDUCE].DIMINISH; else CCWATCH.CCS[effect].DIMINISH = 2 * CCWATCH.CCS[effect].DIMINISH; end end -- ensure if warnable, that WARN is set back to 1 -- 2 = warn at low time already sent -- 3 = broken message seen so no faded message to send if any received if CCWATCH.CCS[effect].WARN > 0 then CCWATCH.CCS[effect].WARN = 1; end end function CCWatch_QueueEffect(effect) local group = CCWATCH.CCS[effect].GROUP; local GROUPS; local ext = ""; if CCWATCH.CCS[effect].ETYPE == ETYPE_BUFF then GROUPS = CCWATCH.GROUPSBUFF; ext = "Buff"; elseif CCWATCH.CCS[effect].ETYPE == ETYPE_DEBUFF then GROUPS = CCWATCH.GROUPSDEBUFF; ext = "Debuff"; else GROUPS = CCWATCH.GROUPSCC; ext = "CC"; end table.insert( GROUPS[group].EFFECT, 1, effect ) local activebarText = getglobal("CCWatchBar"..ext..group.."Text"); activebarText:SetText(effect..": "..CCWATCH.CCS[effect].TARGET); -- if queue was empty show bar if( table.getn(GROUPS[group].EFFECT) == 1 ) then local activebar = getglobal("CCWatchBar"..ext..group); activebar:Show(); if CCWATCH.CCS[effect].COLOR then getglobal("CCWatchBar"..ext..group.."StatusBar"):SetStatusBarColor(CCWATCH.CCS[effect].COLOR.r, CCWATCH.CCS[effect].COLOR.g, CCWATCH.CCS[effect].COLOR.b); end end end function CCWatch_UnqueueEffect(effect) local group = CCWATCH.CCS[effect].GROUP; local GROUPS; local ext = ""; if CCWATCH.CCS[effect].ETYPE == ETYPE_BUFF then GROUPS = CCWATCH.GROUPSBUFF; ext = "Buff"; elseif CCWATCH.CCS[effect].ETYPE == ETYPE_DEBUFF then GROUPS = CCWATCH.GROUPSDEBUFF; ext = "Debuff"; else GROUPS = CCWATCH.GROUPSCC; ext = "CC"; end local index = 0; -- find the effect in the queue, if it's not there index stays 0 table.foreach( GROUPS[group].EFFECT, function(k,v) if( v == effect ) then index = k end end ); if( index ~= 0 ) then -- CCWATCH.CCS[GROUPS[group].EFFECT[index]].TARGET = ""; -- resetting target for mob death removal -- commented because of conflict with DR requiring to keep the target name. -- the name resetting was an unneeded attempt to avoid extra unqueue table.remove( GROUPS[group].EFFECT, index ); end -- if queue isn't empty set new name if( table.getn(GROUPS[group].EFFECT) > 0 ) then local activebarText = getglobal("CCWatchBar"..ext..group.."Text"); local effect = GROUPS[group].EFFECT[1]; activebarText:SetText(effect..": "..CCWATCH.CCS[effect].TARGET); else local activebarText = getglobal("CCWatchBar"..ext..group.."Text"); activebarText:SetText("CCWatch "..ext.." Bar "..group); end end function CCWatchBarCC_OnShow(group) CCWatchBar_OnShow(group, CCWATCH.GROUPSCC, "CC"); end function CCWatchBarDebuff_OnShow(group) CCWatchBar_OnShow(group, CCWATCH.GROUPSDEBUFF, "Debuff"); end function CCWatchBarBuff_OnShow(group) CCWatchBar_OnShow(group, CCWATCH.GROUPSBUFF, "Buff"); end function CCWatchBar_OnShow(group, GROUPS, ext) local barname = "CCWatch"..ext; getglobal(barname):SetScale(CCWATCH.SCALE); -- local status = GetTime(); barname = "CCWatchBar"..ext..group; local activebar = getglobal(barname); activebar:SetBackdropColor(0, 0, 0, 0.35); activebar:SetAlpha(CCWATCH.ALPHA); getglobal(barname.."StatusBar"):SetStatusBarColor(CCWATCH.COTNORMALCOLOR.r, CCWATCH.COTNORMALCOLOR.g, CCWATCH.COTNORMALCOLOR.b); if( table.getn(GROUPS[group].EFFECT) == 0 ) then getglobal(barname.."Text"):SetText("CCWatch Bar "..ext.." "..group); end getglobal(barname.."StatusBarSpark"):SetPoint("CENTER", barname.."StatusBar", "LEFT", 0, 0); end function CCWatchBarCC1_OnShow() CCWatchBarCC_OnShow(1) end function CCWatchBarCC2_OnShow() CCWatchBarCC_OnShow(2) end function CCWatchBarCC3_OnShow() CCWatchBarCC_OnShow(3) end function CCWatchBarCC4_OnShow() CCWatchBarCC_OnShow(4) end function CCWatchBarCC5_OnShow() CCWatchBarCC_OnShow(5) end function CCWatchBarDebuff1_OnShow() CCWatchBarDebuff_OnShow(1) end function CCWatchBarDebuff2_OnShow() CCWatchBarDebuff_OnShow(2) end function CCWatchBarDebuff3_OnShow() CCWatchBarDebuff_OnShow(3) end function CCWatchBarDebuff4_OnShow() CCWatchBarDebuff_OnShow(4) end function CCWatchBarDebuff5_OnShow() CCWatchBarDebuff_OnShow(5) end function CCWatchBarBuff1_OnShow() CCWatchBarBuff_OnShow(1) end function CCWatchBarBuff2_OnShow() CCWatchBarBuff_OnShow(2) end function CCWatchBarBuff3_OnShow() CCWatchBarBuff_OnShow(3) end function CCWatchBarBuff4_OnShow() CCWatchBarBuff_OnShow(4) end function CCWatchBarBuff5_OnShow() CCWatchBarBuff_OnShow(5) end function CCWatch_OnUpdate() if( CCWATCH.STATUS == 0 ) then return end -- local status = GetTime(); table.foreach( CCWATCH.GROUPSCC, CCWatch_GroupCCUpdate ); table.foreach( CCWATCH.GROUPSDEBUFF, CCWatch_GroupDebuffUpdate ); table.foreach( CCWATCH.GROUPSBUFF, CCWatch_GroupBuffUpdate ); end function CCWatch_GroupCCUpdate(group) CCWatch_GroupUpdate(group, CCWATCH.GROUPSCC, "CC"); end function CCWatch_GroupDebuffUpdate(group) CCWatch_GroupUpdate(group, CCWATCH.GROUPSDEBUFF, "Debuff"); end function CCWatch_GroupBuffUpdate(group) CCWatch_GroupUpdate(group, CCWATCH.GROUPSBUFF, "Buff"); end local function ComputeColor(colorhigh, colorlow, high, low, cur) local factor = (cur - low) / (high - low); -- should be divided by 2, but would lead to too dark cases return (colorhigh.r*factor + colorlow.r*(1-factor)), (colorhigh.g*factor + colorlow.g*(1-factor)), (colorhigh.b*factor + colorlow.b*(1-factor)); end local function GetTheRightColorFromTime(curTime) if curTime > 2 * CCWATCH.COTLOWVALUE then return CCWATCH.COTNORMALCOLOR.r, CCWATCH.COTNORMALCOLOR.g, CCWATCH.COTNORMALCOLOR.b; elseif curTime > CCWATCH.COTLOWVALUE then return ComputeColor(CCWATCH.COTNORMALCOLOR, CCWATCH.COTLOWCOLOR, 2*CCWATCH.COTLOWVALUE, CCWATCH.COTLOWVALUE, curTime); elseif curTime > CCWATCH.COTURGEVALUE then return ComputeColor(CCWATCH.COTLOWCOLOR, CCWATCH.COTURGECOLOR, CCWATCH.COTLOWVALUE, CCWATCH.COTURGEVALUE, curTime); else return CCWATCH.COTURGECOLOR.r, CCWATCH.COTURGECOLOR.g, CCWATCH.COTURGECOLOR.b; end end function CCWatch_GroupUpdate(group, GROUPS, ext) local activebar = getglobal("CCWatchBar"..ext..group) if( table.getn(GROUPS[group].EFFECT) > 0 ) then -- active effect on this bar activebar:SetAlpha(CCWATCH.ALPHA); local status = GetTime(); local effect = GROUPS[group].EFFECT[1] local activebarStatusBar = getglobal("CCWatchBar"..ext..group.."StatusBar"); local activebarTextBar = getglobal("CCWatchBar"..ext..group.."StatusBarText"); local str = ""; if( status <= CCWATCH.CCS[effect].TIMER_END ) then -- CC hasn't expired activebarStatusBar:SetMinMaxValues(CCWATCH.CCS[effect].TIMER_START, CCWATCH.CCS[effect].TIMER_END); local sparkPosition = ((status - CCWATCH.CCS[effect].TIMER_START) / (CCWATCH.CCS[effect].TIMER_END - CCWATCH.CCS[effect].TIMER_START)) * CCWATCH.WIDTH; if( CCWATCH.INVERT ) then sparkPosition = CCWATCH.WIDTH - sparkPosition; activebarStatusBar:SetValue(CCWATCH.CCS[effect].TIMER_START + CCWATCH.CCS[effect].TIMER_END - status); else activebarStatusBar:SetValue(status); end local elapsedTime = CCWATCH.CCS[effect].TIMER_END - status; if( sparkPosition < 1 ) then sparkPosition = 1; end local activebarSpark = getglobal("CCWatchBar"..ext..group.."StatusBarSpark"); activebarSpark:SetPoint("CENTER", "CCWatchBar"..ext..group.."StatusBar", "LEFT", sparkPosition, 0); if CCWATCH.TIMERS == 1 then str = format("%.2f", status - CCWATCH.CCS[effect].TIMER_START); elseif CCWATCH.TIMERS == 2 then str = format("%.2f", elapsedTime); end activebarTextBar:SetText(str); if CCWATCH.COLOROVERTIME and not CCWATCH.CCS[effect].COLOR then local r, g, b = GetTheRightColorFromTime(elapsedTime); activebarStatusBar:SetStatusBarColor(r, g, b); end if CCWATCH.CCS[effect].WARN > 0 and bit.band(CCWATCH.WARNMSG, CCW_EWARN_LOWTIME) then if CCWATCH.CCS[effect].TIMER_END - CCWATCH.CCS[effect].TIMER_START > CCWATCH.WARNLOW and CCWATCH.WARNLOW > elapsedTime then if CCWATCH.CCS[effect].WARN == 1 then CCWatchWarn(CCWATCH_WARN_LOWTIME, effect, CCWATCH.CCS[effect].TARGET, CCWATCH.WARNLOW); CCWATCH.CCS[effect].WARN = 2; end elseif CCWATCH.CCS[effect].WARN == 2 then -- reset if ever disconnected while fighting CCWATCH.CCS[effect].WARN = 1; end end elseif status > CCWATCH.CCS[effect].TIMER_END + 0.2 then -- CC has expired. Try to leave room for a fade effect to be catched, then remove anyway CCWatch_RemoveEffect(effect, false) end elseif( activebar:GetAlpha() > 0 ) then -- otherwise fade out this bar if not unlocked if( CCWATCH.STATUS == 1 ) then local activebarText = getglobal("CCWatchBar"..ext..group.."Text"); activebarText:SetText("TimeOut"); local alpha = activebar:GetAlpha() - 0.2; if( alpha > 0 ) then activebar:SetAlpha(alpha); else activebar:Hide(); end end else -- done fading, hide this bar activebar:Hide(); end end local function GetConfCC(k, v) --CCWatch_AddMessage("Updating conf for : "..k); if CCWATCH.CCS[k] then CCWATCH.CCS[k].MONITOR = v.MONITOR; CCWATCH.CCS[k].WARN = v.WARN; CCWATCH.CCS[k].COLOR = v.COLOR; end end local function GetSavedCC(k, v) if v == nil then --CCWatch_AddMessage("Removing "..k); CCWATCH.CCS[k] = nil; return; end if v.GROUP == nil or v.ETYPE == nil or v.LENGTH == nil or v.DIMINISHES == nil then CCWATCH.CCS[k] = nil; return; end --CCWatch_AddMessage("Adding "..k.." ("..type(k)..")"); CCWATCH.CCS[k] = { GROUP = v.GROUP, ETYPE = v.ETYPE, LENGTH = v.LENGTH, DIMINISHES = v.DIMINISHES, WARN = v.WARN, COLOR = v.COLOR, TARGET = "", PLAYER = nil, TIMER_START = 0, TIMER_END = 0, DIMINISH = 1, MONITOR = true } end function CCWatch_LoadConfCCs() -- update array with CC conf table.foreach(CCWatch_Save[CCWATCH.PROFILE].ConfCC, GetConfCC); end function CCWatch_LoadCustomCCs() -- update array with saved CCs table.foreach(CCWatch_Save[CCWATCH.PROFILE].SavedCC, GetSavedCC); end function CCWatch_LoadVariablesOnUpdate(arg1) if not CCWATCH.LOADEDVARIABLES then if(myAddOnsFrame_Register) then myAddOnsFrame_Register(CCWatchDetails, CCWatchHelp); end CCWatch_LoadVariables(); CCWATCH.LOADEDVARIABLES = true; end end function CCWatch_LoadVariables() CCWATCH.PROFILE = UnitName("player").." of "..GetCVar("RealmName"); if CCWatch_Save[CCWATCH.PROFILE] == nil then CCWatch_Save[CCWATCH.PROFILE] = {}; end if CCWatch_Save[CCWATCH.PROFILE].SavedCC == nil then CCWatch_Save[CCWATCH.PROFILE].SavedCC = {}; end if CCWatch_Save[CCWATCH.PROFILE].ConfCC == nil then CCWatch_Save[CCWATCH.PROFILE].ConfCC = {}; end if CCWatch_Save[CCWATCH.PROFILE].status == nil then CCWatch_Save[CCWATCH.PROFILE].status = CCWATCH.STATUS; end if CCWatch_Save[CCWATCH.PROFILE].invert == nil then CCWatch_Save[CCWATCH.PROFILE].invert = false; end if CCWatch_Save[CCWATCH.PROFILE].growth == nil then CCWatch_Save[CCWATCH.PROFILE].growth = 0; end if CCWatch_Save[CCWATCH.PROFILE].scale == nil then CCWatch_Save[CCWATCH.PROFILE].scale = 1; end if CCWatch_Save[CCWATCH.PROFILE].width == nil then CCWatch_Save[CCWATCH.PROFILE].width = 160; end if CCWatch_Save[CCWATCH.PROFILE].alpha == nil then CCWatch_Save[CCWATCH.PROFILE].alpha = 1; end if CCWatch_Save[CCWATCH.PROFILE].arcanist == nil then CCWatch_Save[CCWATCH.PROFILE].arcanist = false; end if CCWatch_Save[CCWATCH.PROFILE].timers == nil then CCWatch_Save[CCWATCH.PROFILE].timers = 1; end if CCWatch_Save[CCWATCH.PROFILE].style == nil then CCWatch_Save[CCWATCH.PROFILE].style = 0; end if CCWatch_Save[CCWATCH.PROFILE].Monitoring == nil then CCWatch_Save[CCWATCH.PROFILE].Monitoring = bit.bor(ETYPE_CC, ETYPE_DEBUFF, ETYPE_BUFF); end if CCWatch_Save[CCWATCH.PROFILE].WarnType == nil then CCWatch_Save[CCWATCH.PROFILE].WarnType = "PARTY"; end if CCWatch_Save[CCWATCH.PROFILE].WarnLow == nil then CCWatch_Save[CCWATCH.PROFILE].WarnLow = 10; end if CCWatch_Save[CCWATCH.PROFILE].WarnMsg == nil then CCWatch_Save[CCWATCH.PROFILE].WarnMsg = bit.bor(CCW_EWARN_FADED, CCW_EWARN_APPLIED, CCW_EWARN_BROKEN, CCW_EWARN_LOWTIME); end if CCWatch_Save[CCWATCH.PROFILE].WarnCustomCC == nil then CCWatch_Save[CCWATCH.PROFILE].WarnCustomCC = ""; end if CCWatch_Save[CCWATCH.PROFILE].ColorOverTime == nil then CCWatch_Save[CCWATCH.PROFILE].ColorOverTime = false; end if CCWatch_Save[CCWATCH.PROFILE].CoTUrgeColor == nil then CCWatch_Save[CCWATCH.PROFILE].CoTUrgeColor = { r=1, g=0, b=0 }; end if CCWatch_Save[CCWATCH.PROFILE].CoTLowColor == nil then CCWatch_Save[CCWATCH.PROFILE].CoTLowColor = { r=1, g=0.5, b=0 }; end if CCWatch_Save[CCWATCH.PROFILE].CoTNormalColor == nil then CCWatch_Save[CCWATCH.PROFILE].CoTNormalColor = { r=1, g=1, b=0 }; end if CCWatch_Save[CCWATCH.PROFILE].CoTUrgeValue == nil then CCWatch_Save[CCWATCH.PROFILE].CoTUrgeValue = 1; end if CCWatch_Save[CCWATCH.PROFILE].CoTLowValue == nil then CCWatch_Save[CCWATCH.PROFILE].CoTLowValue = 5; end if CCWatch_Save[CCWATCH.PROFILE].LeadingTimer == nil then CCWatch_Save[CCWATCH.PROFILE].LeadingTimer = true; end CCWATCH.ARCANIST = CCWatch_Save[CCWATCH.PROFILE].arcanist; CCWatch_LoadConfCCs(); CCWatch_LoadCustomCCs(); CCWatch_UpdateTextures(); -- CCWatch_UpdateClassSpells(false); CCWatch_UpdateClassSpells(true); CCWATCH.STATUS = CCWatch_Save[CCWATCH.PROFILE].status; CCWATCH.INVERT = CCWatch_Save[CCWATCH.PROFILE].invert; CCWATCH.TIMERS = CCWatch_Save[CCWATCH.PROFILE].timers; CCWATCH.GROWTH = CCWatch_Save[CCWATCH.PROFILE].growth; CCWATCH.SCALE = CCWatch_Save[CCWATCH.PROFILE].scale; CCWATCH.WIDTH = CCWatch_Save[CCWATCH.PROFILE].width; CCWATCH.ALPHA = CCWatch_Save[CCWATCH.PROFILE].alpha; CCWATCH.MONITORING = CCWatch_Save[CCWATCH.PROFILE].Monitoring; CCWATCH.WARNTYPE = CCWatch_Save[CCWATCH.PROFILE].WarnType; CCWATCH.WARNLOW = CCWatch_Save[CCWATCH.PROFILE].WarnLow; CCWATCH.WARNMSG = CCWatch_Save[CCWATCH.PROFILE].WarnMsg; CCWATCH.WARNCUSTOMCC = CCWatch_Save[CCWATCH.PROFILE].WarnCustomCC; CCWATCH.COLOROVERTIME = CCWatch_Save[CCWATCH.PROFILE].ColorOverTime; CCWATCH.COTURGECOLOR = CCWatch_Save[CCWATCH.PROFILE].CoTUrgeColor; CCWATCH.COTLOWCOLOR = CCWatch_Save[CCWATCH.PROFILE].CoTLowColor; CCWATCH.COTNORMALCOLOR = CCWatch_Save[CCWATCH.PROFILE].CoTNormalColor; CCWATCH.COTURGEVALUE = CCWatch_Save[CCWATCH.PROFILE].CoTUrgeValue; CCWATCH.COTLOWVALUE = CCWatch_Save[CCWATCH.PROFILE].CoTLowValue; CCWATCH.LEADINGTIMER = CCWatch_Save[CCWATCH.PROFILE].LeadingTimer; CCWatch_SetLeadingTimer(CCWATCH.LEADINGTIMER); if bit.band(CCWATCH.MONITORING, ETYPE_CC) ~= 0 or bit.band(CCWATCH.MONITORING, ETYPE_DEBUFF) ~= 0 then CCWatchObject:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"); CCWatchObject:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"); end if bit.band(CCWATCH.MONITORING, ETYPE_BUFF) ~= 0 then CCWatchObject:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS"); CCWatchObject:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"); end CCWATCH.STYLE = CCWatch_Save[CCWATCH.PROFILE].style; CCWatchCC:SetScale(CCWATCH.SCALE); CCWatchDebuff:SetScale(CCWATCH.SCALE); CCWatchBuff:SetScale(CCWATCH.SCALE); CCWatch_SetWidth(CCWATCH.WIDTH); if( CCWATCH.STATUS == 2 ) then CCWatch_BarUnlock(); end CCWatchOptions_Init(); CCWatch_BarLock(); -- Pure cosmetic for Unlock move local i; for i=1,CCWATCH_MAXBARS do getglobal("CCWatchBarCC"..i.."StatusBarText"):SetText("0.00"); getglobal("CCWatchBarDebuff"..i.."StatusBarText"):SetText("0.00"); getglobal("CCWatchBarBuff"..i.."StatusBarText"):SetText("0.00"); end end function CCWatch_SetLeadingTimer(bLeading) local point; local relpoint; if bLeading then point = "RIGHT"; relpoint = "LEFT"; else point = "LEFT"; relpoint = "RIGHT"; end local i; local bar; for i=1,CCWATCH_MAXBARS do bar = getglobal("CCWatchBarCC"..i.."StatusBarText"); bar:ClearAllPoints(); bar:SetPoint(point, getglobal("CCWatchBarCC"..i.."StatusBar"), relpoint); bar = getglobal("CCWatchBarDebuff"..i.."StatusBarText"); bar:ClearAllPoints(); bar:SetPoint(point, getglobal("CCWatchBarDebuff"..i.."StatusBar"), relpoint); bar = getglobal("CCWatchBarBuff"..i.."StatusBarText"); bar:ClearAllPoints(); bar:SetPoint(point, getglobal("CCWatchBarBuff"..i.."StatusBar"), relpoint); end end function CCWatch_UpdateTextures() local i = 1 while true do local name, rank = GetSpellName(i, BOOKTYPE_SPELL) if not name then return end if CCWATCH.CCS[name] then CCWATCH.CCS[name].TEXTURE = GetSpellTexture(i, BOOKTYPE_SPELL) elseif CCWATCH_SPELLS[name] then if CCWATCH_SPELLS[name].EFFECTNAME then CCWATCH.CCS[CCWATCH_SPELLS[name].EFFECTNAME].TEXTURE = GetSpellTexture(i, BOOKTYPE_SPELL); else CCWatch_AddMessage("Warning : ranked spell '"..name.."' has a different name from its effect, but no effect name in its definition."); end end i = i + 1 end end function CCWatch_UpdateImpGouge(bPrint) local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 2, 1 ); if texture then if bPrint then CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED); end if rank ~= 0 then CCWATCH.CCS[CCWATCH_GOUGE].LENGTH = 4 + rank * 0.5; end elseif CCWATCH.CCS[CCWATCH_GOUGE].LENGTH == nil then CCWATCH.CCS[CCWATCH_GOUGE].LENGTH = 4; end end function CCWatch_UpdateImpGarotte(bPrint) local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 3, 8 ); if texture then if bPrint then CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED); end if rank ~= 0 then CCWATCH.CCS[CCWATCH_GAROTTE].LENGTH = 18 + rank * 3; end elseif CCWATCH.CCS[CCWATCH_GAROTTE].LENGTH == nil then CCWATCH.CCS[CCWATCH_GAROTTE].LENGTH = 18; end end function CCWatch_UpdateKidneyShot(bPrint) local i = 1 while true do local name, rank = GetSpellName(i, BOOKTYPE_SPELL) if not name then if( CCWATCH.CCS[CCWATCH_KS].LENGTH == nil ) then CCWATCH.CCS[CCWATCH_KS].LENGTH = 1; end return end if( name == CCWATCH_KS ) then if bPrint then CCWatch_AddMessage(name.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED); end if( string.sub(rank,string.len(rank)) == "1" ) then CCWATCH.CCS[CCWATCH_KS].LENGTH = 0; else CCWATCH.CCS[CCWATCH_KS].LENGTH = 1; end return end i = i + 1 end end function CCWatch_UpdateImpTrap(bPrint) local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 3, 7 ); if texture then if bPrint then CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED); end if rank ~= 0 then -- Freezing Trap is a true multi rank, hence already updated CCWATCH.CCS[CCWATCH_FREEZINGTRAP].LENGTH = CCWATCH.CCS[CCWATCH_FREEZINGTRAP].LENGTH * (1 + rank * 0.15); end end end function CCWatch_UpdateImpSeduce(bPrint) local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 2, 7 ); if texture then if bPrint then CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED); end if rank ~= 0 then CCWATCH.CCS[CCWATCH_SEDUCE].LENGTH = 15 * (1 + rank * 0.10); end end end function CCWatch_UpdateBrutalImpact(bPrint) local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 2, 4 ); if texture then if bPrint then CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED); end if rank ~= 0 then -- Bash is a true multi rank, hence already updated CCWATCH.CCS[CCWATCH_POUNCE].LENGTH = 2 + rank * 0.50; CCWATCH.CCS[CCWATCH_BASH].LENGTH = CCWATCH.CCS[CCWATCH_BASH].LENGTH + rank * 0.50; end end end function CCWatch_UpdatePermafrost(bPrint) local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 3, 2 ); if texture then if bPrint then CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED); end if rank ~= 0 then -- Frostbolt is a true multi rank, hence already updated CCWATCH.CCS[CCWATCH_CONEOFCOLD].LENGTH = 8 + 0.50 + rank * 0.50; CCWATCH.CCS[CCWATCH_FROSTBOLT].LENGTH = CCWATCH.CCS[CCWATCH_FROSTBOLT].LENGTH + 0.50 + rank * 0.50; end end end function CCWatch_UpdateImpShadowWordPain(bPrint) local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 3, 4 ); if texture then if bPrint then CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED); end if rank ~= 0 then CCWATCH.CCS[CCWATCH_SHADOWWORDPAIN].LENGTH = 18 + rank * 3; end end end function CCWatch_GetSpellRank(spellname, spelleffect, bPrint) local i = 1; local gotone = false; local maxrank = CCWATCH_SPELLS[spellname].RANKS; while true do local name, rank = GetSpellName(i, BOOKTYPE_SPELL) if not name then if not gotone then if bPrint then CCWatch_AddMessage(spellname.." "..CCWATCH_NOTDETECTED); end if( CCWATCH.CCS[spelleffect].LENGTH == nil ) then CCWATCH.CCS[spelleffect].LENGTH = CCWATCH_SPELLS[spellname].DURATION[maxrank]; end end return; end if( name == spellname ) then local currank = 1; while currank <= maxrank do if( tonumber(string.sub(rank,string.len(rank))) == currank) then if bPrint then CCWatch_AddMessage(spellname.." "..CCWATCH_RANK.." "..currank.." "..CCWATCH_DETECTED); end CCWATCH.CCS[spelleffect].LENGTH = CCWATCH_SPELLS[spellname].DURATION[currank]; gotone = true; end currank = currank + 1; end end i = i + 1 end end function CCWatch_UpdateClassSpells(bPrint) local _, eclass = UnitClass("player"); CCWatchOptionsFrameArcanist:Hide(); if eclass == "ROGUE" then CCWatch_GetSpellRank(CCWATCH_SAP, CCWATCH_SAP, bPrint); CCWatch_UpdateImpGouge(bPrint); CCWatch_UpdateKidneyShot(bPrint); if CCWatch_ConfigBuff ~= nil then CCWatch_UpdateImpGarotte(bPrint); end elseif eclass == "WARLOCK" then CCWatch_GetSpellRank(CCWATCH_FEAR, CCWATCH_FEAR, bPrint); CCWatch_GetSpellRank(CCWATCH_BANISH, CCWATCH_BANISH, bPrint); CCWatch_UpdateImpSeduce(bPrint); elseif eclass == "PALADIN" then CCWatch_GetSpellRank(CCWATCH_HOJ, CCWATCH_HOJ, bPrint); if CCWatch_ConfigBuff ~= nil then CCWatch_GetSpellRank(CCWATCH_DIVINESHIELD, CCWATCH_DIVINESHIELD, bPrint); end elseif eclass == "HUNTER" then CCWatch_GetSpellRank(CCWATCH_FREEZINGTRAP_SPELL, CCWATCH_FREEZINGTRAP, bPrint); CCWatch_GetSpellRank(CCWATCH_SCAREBEAST, CCWATCH_SCAREBEAST, bPrint); CCWatch_UpdateImpTrap(bPrint); elseif eclass == "PRIEST" then CCWatch_GetSpellRank(CCWATCH_SHACKLE, CCWATCH_SHACKLE, bPrint); if CCWatch_ConfigDebuff ~= nil then CCWatch_UpdateImpShadowWordPain(bPrint); end elseif eclass == "MAGE" then CCWatch_GetSpellRank(CCWATCH_POLYMORPH, CCWATCH_POLYMORPH, bPrint); if CCWatch_ConfigDebuff ~= nil then CCWatch_GetSpellRank(CCWATCH_FROSTBOLT, CCWATCH_FROSTBOLT, bPrint); CCWatch_GetSpellRank(CCWATCH_FIREBALL, CCWATCH_FIREBALL, bPrint); CCWatch_UpdatePermafrost(bPrint); end CCWatchOptionsFrameArcanist:Show(); if CCWATCH.ARCANIST then CCWATCH.CCS[CCWATCH_POLYMORPH].LENGTH = CCWATCH.CCS[CCWATCH_POLYMORPH].LENGTH + 15; end elseif eclass == "DRUID" then CCWatch_GetSpellRank(CCWATCH_ROOTS, CCWATCH_ROOTS, bPrint); CCWatch_GetSpellRank(CCWATCH_HIBERNATE, CCWATCH_HIBERNATE, bPrint); CCWatch_GetSpellRank(CCWATCH_BASH, CCWATCH_BASH, bPrint); CCWatch_UpdateBrutalImpact(bPrint); end end function CCWatch_Help() CCWatch_AddMessage(CCWATCH_FULLVERSION..CCWATCH_HELP1); CCWatch_AddMessage(CCWATCH_HELP2); CCWatch_AddMessage(CCWATCH_HELP3); CCWatch_AddMessage(CCWATCH_HELP4); CCWatch_AddMessage(CCWATCH_HELP5); CCWatch_AddMessage(CCWATCH_HELP6); CCWatch_AddMessage(CCWATCH_HELP7); CCWatch_AddMessage(CCWATCH_HELP8); CCWatch_AddMessage(CCWATCH_HELP9); CCWatch_AddMessage(CCWATCH_HELP10); CCWatch_AddMessage(CCWATCH_HELP11); CCWatch_AddMessage(CCWATCH_HELP12); CCWatch_AddMessage(CCWATCH_HELP13); CCWatch_AddMessage(CCWATCH_HELP14); CCWatch_AddMessage(CCWATCH_HELP15); CCWatch_AddMessage(CCWATCH_HELP16); CCWatch_AddMessage(CCWATCH_HELP17); end function CCWatch_SetWidth(width) local i, j, k; for j, k in ipairs({"CC","Debuff","Buff"}) do for i=1,CCWATCH_MAXBARS do getglobal("CCWatchBar"..k..i):SetWidth(width + 10); getglobal("CCWatchBar"..k..i.."Text"):SetWidth(width); getglobal("CCWatchBar"..k..i.."StatusBar"):SetWidth(width); end getglobal("CCWatch"..k):SetWidth(width + 10); end end function CCWatch_CheckRecentTargets(mobname) local target = UnitName("target"); -- Simple compare if using current target monitoring if CCWATCH.STYLE == 0 then return mobname == target; end local index = 0; -- Check mobname against the list table.foreach( CCWATCH.LASTTARGETS, function(k,v) if( v.TARGET == mobname ) then index = k end end ); if index ~= 0 then return true; end -- return false if target not found return false; end function CCWatch_AddLastTarget(mobname, time) local lt_struct = {} lt_struct.TARGET = mobname; lt_struct.TIME = time; -- CCWatch_AddMessage("Adding "..mobname); -- if the array is full if table.getn(CCWATCH.LASTTARGETS) >= 5 then -- remove the oldest target local oldest = 0; local index = 0; table.foreach(CCWATCH.LASTTARGETS, function(k,v) if oldest == 0 then oldest = v.TIME; index = k; elseif( v.TIME < oldest ) then oldest = v.TIME; index = k; end end); -- CCWatch_AddMessage("Removing old target : "..CCWATCH.LASTTARGETS[index].TARGET); table.remove(CCWATCH.LASTTARGETS, index); end table.insert( CCWATCH.LASTTARGETS, lt_struct ) -- DEBUG : -- local targets = "Current targets : " -- table.foreach(CCWATCH.LASTTARGETS, function(k,v) targets = targets.."'"..v.TARGET.."',"; end); -- CCWatch_AddMessage(targets); end function CCWatch_AddMessage(msg) DEFAULT_CHAT_FRAME:AddMessage(" "..msg); end