vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:

local mod = klhtm
local me = { }
mod.net = me

--[[
KTM_Net.lua

This module has all the code for operating the chat channel and sending KLHTM messages on it. Note that it doesn't
deal with parsing / interpreting messages received from the chat channel - this is all done in KTM_NetIn.lua.

]]

me.channelname = ""
me.channelnumber = 0
me.source = ""

me.manualchannel = nil -- manual override

me.lastmtsender = ""    -- name of the player who sent the last mt
me.lastmtstring = ""    -- name of the last mt, as sent by the player
me.lastmttime = 0               -- time you last updated MT
me.mtrepeattime = 10.0

-- Special onupdate method from Core.lua
me.onupdate = function()
        
        me.updatethreattoraid()
        me.checkversionquery()
        me.checkadvertise()
        
        -- check to repeat mt string
        if me.lastmtsender == UnitName("player") then
                
                -- check if you are still an assistant
                if mod.unit.isplayerofficer(UnitName("player")) == nil then
                        me.lastmtsender = ""
                        
                elseif GetTime() > me.lastmttime + me.mtrepeattime then
                        
                        -- resend and reset timer
                        me.lastmttime = GetTime()
                        
                        -- Now, was it a clear or a name?
                        if me.lastmtstring == "clear" then
                                
                                -- temporary: only send this to new versions (or else old versions might get spammed!)
                                if mod.isnewwowversion then
                                        me.clearmastertarget()
                                end
                                
                        else
                                -- temporary: only send this to new versions (or else old versions might get spammed!)
                                if mod.isnewwowversion then
                                        me.sendmessage("mtpoll " .. me.lastmtstring)
                                end
                        end
                end
        end
end


------------------------------------------------------------------------------------------------

---------------------------------
--    Chat Channel Operation   --
---------------------------------

-- return: number, name, method
me.getchannel = function()

        local name
        local number
        local test

        -- use the current channel, if that works
        number, name = GetChannelName(me.channelname)
        
        if number > 0 then
                return number, name, me.source
        end
        
        -- Channel broken. look for oRA, CT_RA, manual set channels.
        
        -- First priority: manual override
        if me.manualchannel then
                number, name = GetChannelName(me.manualchannel)
                
                if number > 0 then
                        me.channelnumber = number
                        me.channelname = name
                        me.source = mod.string.get("print", "network", "channel", "manual")
                        return number, name, me.source
                end
        end
        
        -- Second priority: oRA
        if oRA_Core then
                test = oRA_Core:GetOpt("channel")
                
                if test then 
                        number, name = GetChannelName(test)
                        
                        if number > 0 then
                                me.channelnumber = number
                                me.channelname = name
                                me.source = mod.string.get("print", "network", "channel", "ora")
                                return number, name, me.source
                        end
                end
        end
        
        -- Third priority: CT_RA
        if CT_RA_Channel then
                number, name = GetChannelName(CT_RA_Channel)
                
                if number > 0 then
                        me.channelnumber = number
                        me.channelname = name
                        me.source = mod.string.get("print", "network", "channel", "ctra")
                        return number, name, me.source
                end
        end
        
        -- can't find it!
        return 0 
end


--[[
mod.net.sendmessage(message)
Sends a message to the KLHTM chat channel.
<message> is a string. Don't put the "KLHTM " header on it; that's what this method does.
Return: true if the mod could find the right channel, false otherwise.
]]
me.sendmessage = function(message)
        
        -- 1.12 override
        if mod.isnewwowversion then

                if GetNumRaidMembers() > 0 then
                        SendAddonMessage("KLHTM", message, "RAID")
                
                elseif GetNumPartyMembers() > 0 then
                        SendAddonMessage("KLHTM", message, "PARTY")
                
                else
                        -- Send directly to our input handler
                        mod.netin.messagein(UnitName("player"), message, 1)
                end
                
                return true
        end
        
        local channelnumber = me.getchannel()
        
        if channelnumber > 0 then
                
                -- add KLHTM header
                message = "KLHTM " .. message
                
                -- send
                SendChatMessage(message, "CHANNEL", nil, channelnumber)
                
                -- debug
                if mod.out.checktrace("info", me, "message") then
                        mod.out.printtrace(string.format("Sent this message: %s.", message))
                end
                
                return true 
        
        else
        
                return false
        end
        
end


------------------------------------------------------------------------------------------------

---------------------------------
--    Special Raid Commands    --
---------------------------------

--[[ 
me.checkpermission()
Returns: non-nil iff you are allowed to send special commands (raid assistant / party leader, etc)
]]
me.checkpermission = function()

        if mod.unit.isplayerofficer(UnitName("player")) == true then
                return true
                
        else
                mod.out.print(mod.string.get("print", "network", "raidpermission"))
                return
        end
        
end
        
--[[
mod.net.clearmastertarget()
Sends a message to clear the master target. This is called from "/ktm mastertarget", or clicking the master target button
when you have no target.
]]
me.clearmastertarget = function()
        
        if me.checkpermission() == nil then
                return
        end
        
        me.sendmessage("cleartarget")
                
end

--[[
mod.net.sendmastertarget()
Sends a message to set the master target to your current target. The name of your current target, as you see it, is sent along with the command, in case someone is out of (targetting) range of your target. This is called from 
"/ktm mastertarget", or clicking the master target button when you have a target.
]]
me.sendmastertarget = function()

        if me.checkpermission() == nil then
                return
        end
        
        if UnitName("target") == nil then
                mod.out.print(mod.string.get("print", "network", "needtarget"))
                return 
        end
        
        me.sendmessage("target " .. UnitName("target"))
        
end

--[[
mod.net.clearraidthreat()
Commands everyone in the raid to reset their threat. Called when you type "/ktm resetraid" or click the "clear threat"
button on the GUI (which is not visible by default).
]]
me.clearraidthreat = function()
        
        if me.checkpermission() == nil then
                return
        end
        
        me.sendmessage("clear")
        
end

-- Commands in the Boss Section

me.startspellreporting = function()

        if me.checkpermission() == nil then
                return
        end
        
        me.sendmessage("spellstart")
                
end

me.stopspellreporting = function()
        
        if me.checkpermission() == nil then
                return
        end
        
        me.sendmessage("spellstop")

end

me.reportspelleffect = function(spellname, bossname, result, value1, value2)
        
        if result == "miss" then
                me.sendmessage(string.format("spelleffect \"%s\" \"%s\" %s", spellname, bossname, result))
                
        else
                me.sendmessage(string.format("spelleffect \"%s\" \"%s\" %s %s %s", spellname, bossname, result, value1, value2))
        end
        
end

me.setspellvalue = function(spellid, bossid, parameter, value)

        if me.checkpermission() == nil then
                return
        end
        
        me.sendmessage(string.format("spellvalue %s %s %s %s", spellid, bossid, parameter, value))

end

-- syntax: <spellid> <bossid> <parameter> <value>
--[[
        if it succeeds, it will return just the value that is set.
        if it fails, it will return nil, then the error message.
]]
me.checkspellvaluesyntax = function(allvalues)
                        
        local x, spellid, bossid, parameter, value, key, message

        -- Check their first argument, <spellid>, is valid
        spellid = allvalues[1]
        if (spellid == nil) or (mod.boss.bossattacks[spellid] == nil) then
                
                message = "The argument |cffffff00" .. tostring(spellid) .. "|r does not match any boss spell id. Valid spellids are|cffffff00"
                
                for key, value in mod.boss.bossattacks do
                        message = message .. " " .. key
                end

                message = message .. "|r."
                return nil, message
        end
        
        -- Check their second argument, <bossid>, is valid
        local dataset = mod.boss.bossattacks[spellid]
        
        bossid = allvalues[2]
        if (bossid == nil) or (dataset[bossid] == nil) then
                
                message = "The argument |cffffff00" .. tostring(bossid) .. "|r does not match any boss that uses the spell |cffffff00" .. mod.string.get("boss", "spell", spellid) .. "|r. Valid bossids are|cffffff00"
                
                for key, value in dataset do
                        message = message .. " " .. key
                end

                message = message .. "|r."
                return nil, message
        end
        
        -- Check their third argument, <parameter>, is valid
        dataset = dataset[bossid]
        
        parameter = allvalues[3]
        if (parameter == nil) or (dataset[parameter] == nil) then
                
                message = "The argument |cffffff00" .. tostring(parameter) .. "|r does not match any parameter that can be set. Valid parameters are|cffffff00"
                
                for key, valud in dataset do
                        message = message .. " " .. key
                end

                message = message .. "|r."
                return nil, message
        end
        
        -- 4th parameter is value
                                                
        -- multiplier / addition: need number
        if (parameter == "addition") or (parameter == "multiplier") then
                value = tonumber(allvalues[4])
                
                if value == nil then
                        
                        message = "The argument |cffffff00" .. tostring(allvalues[4]) .. "|r is not a number."
                        return nil, message
                end
                
        elseif parameter == "ticks" then
                value = tonumber(allvalues[4])
                
                if (value == nil) or (math.floor(value) ~= value) or (value < 1) then
                        
                        message = "The argument |cffffff00" .. tostring(allvalues[4]) .. "|r is not a positive integer."
                        return nil, message
        end
                
        elseif parameter == "effectonmiss" then
                
                if value == "true" then
                        value = true
                
                elseif value == "false" then
                        value = false
                
                else
                        message = "The argument |cffffff00" .. tostring(allvalues[4]) .. "|r is not a boolean value."
                        return nil, message
                end
                
        elseif parameter == "type" then
                
                if (value ~= "physical") or (value ~= "debuff") or (value ~= "spell") then
                        
                        message = "The argument |cffffff00" .. tostring(allvalues[4]) .. "|r is not one of |cffffff00 physical debuff spell|r."
                        return nil, message
                end
        end
        
        -- it worked!
        return value
end


me.versionnotify = function()

        if me.checkpermission() == nil then
                return
        end
        
        me.sendmessage(string.format("version %d.%d", mod.release, mod.revision))
        mod.out.print(mod.string.get("print", "network", "upgradenote"))
        
end

me.versionquery = function()
        
        if me.checkpermission() == nil then
                return
        end
        
        -- clear the version table
        local key

        for key, _ in me.raidversions do
                table.remove(me.raidversions, key)
        end
        
        -- set the timeout for responses
        me.versionquerytimeout = GetTime() + 3
        
        -- Notify the user
        mod.out.print(mod.string.get("print", "network", "versionrequest"))
        
        -- send the message
        me.sendmessage("versionquery")
                
end

me.setraidknockbackvalue = function(value, attack)
        
        if me.checkpermission() == nil then
                return
        end
        
        if mod.boss.isknockbackdiscoveryactive == false then
                mod.out.print(mod.string.get("print", "network", "knockbackinactive"))
        else
                me.sendmessage("knockbackvalue " .. value .. " " .. attack)
        end
        
end

me.sendknockbackevent = function(enemy, ability, value)

        if (mod.boss.isknockbackdiscoveryactive == true) and (enemy == mod.boss.mastertarget) then
        
                me.sendmessage("knockaway " .. math.ceil(0.5 + mod.table.getraidthreat()))
                me.sendmessage(string.format("knockawaytext {%s, %s, %s}", enemy, ability, value))
        end
        
end

-- don't send an event if one has already been received and confirmed recently.
me.sendevent = function(event)
        
        me.sendmessage("event " .. event)
        
end

-- Version Querying Stuff. Key = release number, value = array of names
me.raidversions = { }
me.versionquerytimeout = 0 -- 0 = inactive, > 0 = active. Return value of GetTime()

me.addversionresponse = function(playername, version)

        local versionstring = tostring(version)
        
        -- ignore unless we are checking versions
        if me.versionquerytimeout > 0 then
        
                if me.raidversions[versionstring] == nil then
                        me.raidversions[versionstring] = { }
                end
                
                me.raidversions[versionstring][playername] = true
        end

end


-- When we do "/ktm version query", the rest of the raid has 3 seconds to respond.
me.checkversionquery = function()
        
        if me.versionquerytimeout == 0 then
                return
        end
        
        if GetTime() > me.versionquerytimeout then
                
                -- print it out and stuff
                me.versionquerytimeout = 0
                
                local message
                local key
                local value
                local key2
                local namesfound = { }
                
                for key, value in me.raidversions do
                        message = string.format(mod.string.get("print", "network", "versionrecent"), key)
                        
                        for key2, _ in value do
                                message = message .. key2 .. ", "
                                namesfound[key2] = true
                        end
                        
                        message = message .. " }."
                        mod.out.print(message)
                        
                        table.remove(me.raidversions, key)
                end
                
                -- Now print the people who have out of date versions
                message = mod.string.get("print", "network", "versionold")
                for key, _ in mod.table.raiddata do
                        if namesfound[key] == nil and mod.unit.isplayeringroup(key) == true then
                                namesfound[key] = true
                                message = message .. key .. ", "
                        end
                end
                
                message = message .. " }."
                mod.out.print(message)
                
                -- Now print out people who are not talking to us
                message = mod.string.get("print", "network", "versionnone")
                
                for value = 1, 40 do
                        key = GetRaidRosterInfo(value)
                        if (key ~= nil) and (namesfound[key] == nil) then
                                namesfound[key] = true
                                message = message .. key .. ", "
                        end
                end
                
                message = message .. " }."
                mod.out.print(message)
                
        end
end

me.lastthreatupdate = 0 -- value of GetTime(). When we last posted our threat to the raid
me.minimumupdateinterval = 0.5 -- minimum time, in seconds, between threat updates to the raid
me.idleupdateinterval = 10.0 -- how often to update when our value is not changing
me.lastthreatvaluesent = -1 -- the name says it all, really

--[[
me.updatethreattoraid()
Posts your threat value to the KLHTM channel if necessary. You will send your threat at most once every
<me.minimumupdateinterval> = 0.5 seconds. If your threat value is unchanged, you will repeat it once every 10
seconds only. If you aren't in a party or raid, you won't repeat your value if it is constant.
]]
me.updatethreattoraid = function()
        
        local interval
        local myraidthreat
        
        if mod.my.states.incombat.value == true then
                myraidthreat = math.floor(0.5 + mod.table.getraidthreat())
        else
                myraidthreat = 0
        end
        
        if myraidthreat == me.lastthreatvaluesent then
                interval = me.idleupdateinterval
        
                -- check for solo, then no updates
                if GetNumRaidMembers() == 0 and GetNumPartyMembers() == 0 then
                        return
                end 
                
                -- also don't send idle updates when afk
                if mod.my.states.afk.value == true then
                        return
                end
                
        else
                interval = me.minimumupdateinterval
                
        end
        
        -- check update frequency
        if GetTime() < me.lastthreatupdate + interval then
                return -- only just sent an update. Wait a bit to send the next one.
        end
        
        -- OK. Send.
        local message = "threat " .. myraidthreat
        if mod.isnewwowversion then
                message = "t " .. myraidthreat
        end
        
        if me.sendmessage(message) == nil then
                if mod.out.checktrace("warning", me, "channel") then
                        mod.out.printtrace("Threat was not updated because the CTRA Channel is not set up properly.")
                end
        end
        
        me.lastthreatupdate = GetTime()
        me.lastthreatvaluesent = myraidthreat

end

--------------------------------------------------------------------------------------------------

-------------------------------------------------------
--    Advertising KLHTM to people who pull aggro!    --
-------------------------------------------------------

me.isadvertising = false
me.lastadvert = 0
me.advertinterval = 300 -- seconds

--[[
mod.net.toggleadvertise()
Switch the advertising function on or off.
]]
me.toggleadvertise = function()

        me.isadvertising = not me.isadvertising
        
        if me.isadvertising == true then
                mod.out.print(mod.string.get("print", "network", "advertisestart"))
        else
                mod.out.print(mod.string.get("print", "network", "advertisestop"))
        end

end

me.raidnumbers = { } -- {1, 2, 3, ..., 40}

for x = 1, 40 do
        me.raidnumbers[x] = x
end

--[[
me.checkadvertise()
Looks for people who have pulled aggro but don't have KLHTM, and tells them to get it. A message will be sent no more than
once every <me.advertinterval> = 5 minutes. Messages will be sent to non-warriors who are being targetted by a mob, so it's
not a complete guarantee that they have aggro.
]]
me.checkadvertise = function()

        if me.isadvertising == false then
                return
        end
        
        -- don't spam
        if GetTime() < me.lastadvert + me.advertinterval then
                return
        end

        -- look for someone who has aggro, is not a warrior, is not in the raid threat
        if GetNumRaidMembers() <= 0 then
                return
        end
        
        local target = ""
        local player = ""
        local x
        
        -- make it a random permutation of the raid, to stop bugging one person
        me.scrambleraid(me.raidnumbers)
        
        for y = 1, 40 do
                
                -- get x from scrambled array
                x = me.raidnumbers[y]
                
                -- there is a raid player
                target = "raid" .. x
                if UnitExists(target) == 1 then
                        
                        -- the player is targetting a mob
                        target = target .. "target"
                        if UnitExists(target) == 1 and UnitIsFriend("player", target) ~= 1 then
                        
                                -- mob has another player targetted
                                player = target .. "target"
                                if UnitIsFriend("player", player) == 1 then
                                
                                        -- player is not yourself, not a warrior, is a player
                                        if (UnitIsPlayer(player) == 1) and (UnitName("player") ~= UnitName(player)) then
                                        
                                                local _, class = UnitClass(player)
                                                if class ~= "WARRIOR" then
                                                        
                                                        -- check they arne't using the meter
                                                        if mod.table.raiddata[UnitName(player)] == nil then
                                                        
                                                                -- send them a message
                                                                SendChatMessage(string.format(mod.string.get("print", "network", "advertisemessage"), UnitName(target)), "WHISPER", nil, UnitName(player))
                                                                me.lastadvert = GetTime()
                                                                return
                                                        end
                                                end
                                        end
                                end
                        end
                end
        end
end

--[[
me.scrambleraid(numbers)
Slightly scrambles the array <numbers>. Picks 10 random pairs and swaps them. Since this scramble method gets called
each time we check, the array will be sufficiently inconstant all the time.
]]
me.scrambleraid = function(numbers)

        local x
        local temp
        local box1
        local box2
        
        for x = 1, 10 do
                box1 = math.random(1, 40)
                box2 = math.random(1, 40)
                
                temp = numbers[box1]
                numbers[box1] = numbers[box2]
                numbers[box2] = temp
        end
        
end                                     
                        

Generated by GNU Enscript 1.6.5.90.