vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
--[[
        DynamicData

        By sarf

        This AddOn allows you to access dynamic data in WoW without being forced to rely on strange Blizzard functions

        Thanks goes to the Sea people, the UltimateUI team and finally the nice (but strange) people at 
         #ultimateuitesters and Blizzard.
        
        UltimateUIUI URL:
        http://www.ultimateuiui.org/forums/viewtopic.php?t=NOT_YET_ANNOUNCED
        
   ]]


-- Utility functions
DynamicData.util = {

-- public functions     

        -- 
        -- addOnWhateverHandler (func)
        --
        --  Adds a function name that will be called on whatever.
        --
        addOnWhateverHandler = function (list, func)
                for k, v in list do
                        if ( v == func ) then
                                return false;
                        end
                end
                table.insert(list, func);
                return true;
        end;

        -- 
        -- removeOnWhateverHandler (list, func)
        --
        --  Removes the specified function, so that it will not be called on whatever.
        --
        removeOnWhateverHandler = function (list, func)
                local index = nil;
                for k, v in list do
                        if ( v == func ) then
                                index = k;
                                break;
                        end
                end
                if ( index ) then
                        table.remove(list, index);
                        return true;
                else
                        return false;
                end
        end;

        -- 
        -- notifyWhateverHandlers (list, ...)
        --
        -- Args: 
        --  list - the list of handlers
        -- 
        --  Notifies all handlers that an Whatever has occurred.
        --
        notifyWhateverHandlers = function (list, ...) 
                local func = nil;
                for k, v in list do
                        func = v;
                        if ( arg ) then
                                func(unpack(arg));
                        else
                                func();
                        end
                end
        end;

        --
        -- removeEntryFromList (value, list, limit)
        --
        --  Removes value from the list, up to limit times. 
        --  If limit is not specified, it will be removed once. If limit is 0 or lower, all values will be removed.
        --
        removeEntryFromList = function (value, list, limit)
                if ( not limit ) then limit = 1; end
                if ( limit <= 0 ) then limit = -1; end
                local hasRemoved = false;
                local found = true;
                local index = 1;
                while ( found ) do
                        found = false;
                        index = DynamicData.util.getIndexInList(value, list);
                        if ( index ) then
                                found = true;
                                table.remove(list, index);
                                hasRemoved = true;
                                if ( limit > 0 ) then
                                        limit = limit - 1;
                                end
                                if ( limit == 0 ) then
                                        break;
                                end
                        end
                end
                return hasRemoved;
        end;

        --
        -- isThingyEqual(value, valueCheck)
        --
        --  compares two things and sees if they are equal to each other
        -- 
        isThingyEqual = function(value, valueCheck)
                if ( value == valueCheck ) then
                        return true;
                else
                        if ( type(valueCheck) == "table" ) then
                                return DynamicData.util.isStringInList(value, valueCheck);
                        end
                        return false;
                end
        end;

        --
        -- getIndexInList (value, list, start)
        --
        --  Retrieves the index of value in list, starting at start.
        --  Start is 1 if unspecified.
        --
        getIndexInList = function (value, list, start)
                if ( not value ) then
                        return nil;
                end
                if ( not list ) then
                        return nil;
                end
                if ( type(list) ~= "table" ) and ( type(value) == "table" ) then
                        local tmp = list;
                        list = value;
                        value = tmp;
                end
                local found = true;
                local index = nil;
                local listSize = table.getn(list);
                local oldStart = start;
                if ( listSize > 0 ) then
                        if ( not start ) then start = 1; end
                        for i = start, listSize do
                                if ( DynamicData.util.isThingyEqual(list[i], value ) ) then
                                        index = i;
                                        break;
                                end
                        end
                        if ( not index ) then
                                for k, v in list do
                                        if ( ( not oldStart ) or ( oldStart >= k ) ) and ( DynamicData.util.isThingyEqual(v, value ) ) then
                                                index = k;
                                                break;
                                        end
                                end
                        end
                else
                        for k, v in list do
                                if ( DynamicData.util.isThingyEqual(v, value ) ) then
                                        index = k;
                                        break;
                                end
                        end
                end
                return index;
        end;


        --
        -- isStringInList (str, list)
        --
        --  Returns true if str is a value of list.
        --
        isStringInList = function (param1, param2)
                if ( not param1 ) or ( not param2 ) then
                        return false;
                end
                local str = param1;
                local list = param2;
                if ( type(param1) == "table" ) then
                        str = param2;
                        list = param1;
                end
                for k, v in list do
                        if ( v == str ) then
                                return true;
                        end
                end
                return false;
        end;
        
        --
        -- safeToUseTooltips ()
        --
        --  Checks if it is "safe" to use tooltips to dump information.
        --  Basically, it checks if one (or more) particular frames are visible.
        --  If they are, it is not safe to use tooltips.
        safeToUseTooltips = function (ignoreList)
                local frame = nil;
                local list = {};
                if ( DynamicData.util.tooltipUsingFrames ) then
                        for k, v in DynamicData.util.tooltipUsingFrames do
                                list[v] = 1;
                        end
                end
                if ( ignoreList ) then
                        for k, v in ignoreList do
                                list[v] = nil;
                        end
                end
                for k, v in list do
                        frame = getglobal(k);
                        if ( ( frame ) and ( frame:IsVisible() ) ) then
                                return false;
                        end
                end
                return true;
        end;

        --
        -- clearTooltipStrings (tooltipName)
        --
        --  Clears a tooltip of text.
        --
        clearTooltipStrings = function (tooltipName)
                -- local tooltip = getglobal(tooltipName);
                if ( tooltip ) then
                        local textObj = nil;
                        for i = 1, 15 do
                                textObj = getglobal(tooltipName.."TextLeft"..i);
                                if ( textObj ) then
                                        textObj:SetText("");
                                end
                                textObj = getglobal(tooltipName.."TextRight"..i);
                                if ( textObj ) then
                                        textObj:SetText("");
                                end
                        end
                end
        end;

        --
        -- getNameFromTooltip (tooltipName)
        --
        --  Retrieves the name from the specified tooltip.
        --
        getNameFromTooltip = function (tooltipName)
                local strings = DynamicData.util.getTooltipStrings(tooltipName);
                if ( strings ) and ( strings[1] ) then
                        return strings[1].left;
                else
                        return nil;
                end
        end;
        
        --
        -- getTooltipStrings (tooltipName)
        --
        --  Retrieves strings from the specified tooltip.
        --  It basically takes all strings in the tooltip and puts them in an array and returns the array.
        --  All credit to Sea for this one, even though it is not copy/pasted! ;)
        --
        getTooltipStrings = function (tooltipName, strings)
                if ( not strings ) then
                        strings = {};
                end
                local tooltip = getglobal(tooltipName);
                if ( tooltip ) then
                        local textObj = nil;
                        local textLeft = nil;
                        local textRight = nil;
                        local hasElement = false;
                        for i = 1, 15 do
                                hasElement = false;
                                textObj = getglobal(tooltipName.."TextLeft"..i);
                                if ( textObj ) then
                                        textLeft = textObj:GetText();
                                        if ( textLeft ) and ( strlen(textLeft) > 0 ) then
                                                hasElement = true;
                                        end
                                else
                                        textLeft = nil;
                                end
                                textObj = getglobal(tooltipName.."TextRight"..i);
                                if ( textObj ) then
                                        textRight = textObj:GetText();
                                        if ( textRight ) and ( strlen(textRight) > 0 ) then
                                                hasElement = true;
                                        end
                                else
                                        textRight = nil;
                                end
                                if ( hasElement ) then
                                        strings[i] = {};
                                        strings[i].left = textLeft;
                                        strings[i].right = textRight;
                                end
                        end
                end
                return strings;
        end;

        --
        -- getItemTooltipInfo (bag, slot, tooltipName)
        --
        --  Retrieves info about a particular item.
        --
        getItemTooltipInfo = function (bag, slot, tooltipName, strings)
                if ( not tooltipName ) then
                        tooltipName = "DynamicDataTooltip";
                end
                local tooltip = getglobal(tooltipName);
                DynamicData.util.clearTooltipStrings(tooltipName);
                if ( bag > -1 ) then
                        DynamicData.util.protectTooltipMoney();
                        tooltip:SetBagItem(bag, slot);
                        DynamicData.util.unprotectTooltipMoney();
                        strings = DynamicData.util.getTooltipStrings(tooltipName, strings);
                else
                        if ( slot == -1 ) then
                                return nil;
                        end
                        DynamicData.util.protectTooltipMoney();
                        local hasItem, hasCooldown = tooltip:SetInventoryItem("player", slot);
                        DynamicData.util.unprotectTooltipMoney();
                        strings = DynamicData.util.getTooltipStrings(tooltipName, strings);
                        if ( not hasItem) then
                                DynamicData.util.clearTooltipStrings(tooltipName);
                                if ( strings[1] ) then
                                        strings[1].left = "";
                                end
                        end
                end
                return strings;
        end;

        --
        -- getCurrentAndMaxDurability (strings)
        --
        --  Extracts durability info from an array that correspond to a tooltip.
        --
        getCurrentAndMaxDurability = function (strings)
                if ( not strings ) then
                        return nil, nil;
                end
                local index = nil;
                local index2 = nil;
                local tmp = nil;
                for k, v in strings do
                        if ( v.left )  then
                                index = strfind(v.left, DYNAMICDATA_DURABILITY);
                                if ( index ) then
                                        tmp = strsub(v.left, strlen(DYNAMICDATA_DURABILITY)+1);
                                        while ( strsub(tmp, 1, 1) == " " ) do
                                                tmp = strsub(tmp, 2);
                                        end
                                        index = strfind(tmp, " ");
                                        index2 = strfind(tmp, "/");
                                        if ( index2 < index ) then
                                                local indexTmp = index;
                                                index = index2;
                                                index2 = indexTmp;
                                        end
                                        local currentDurability = tonumber(strsub(tmp, 1, index-1));
                                        tmp = strsub(tmp, index2+1);
                                        while ( strsub(tmp, 1, 1) == " " ) do
                                                tmp = strsub(tmp, 2);
                                        end
                                        index = strfind(tmp, " ");
                                        if ( not index ) then
                                                index = strlen(tmp);
                                        end
                                        local maxDurability = tonumber(strsub(tmp, 1, index));
                                        return currentDurability, maxDurability;
                                end                                     
                        end
                end
                return nil, nil;
        end;
        
        --
        -- getDPS (strings)
        --
        --  Extracts DPS info from an array that correspond to a tooltip.
        --
        getDPS = function (strings)
                if ( not strings ) then
                        return nil, nil;
                end
                local tmpNumber = nil;
                local tmp = nil;
                for k, v in strings do
                        for tmp in string.gfind(v.left, DYNAMICDATA_DPS_GSUB) do 
                                tmpNumber = tonumber(tmp);
                                if ( tmpNumber ) then
                                        return tmpNumber;
                                end
                        end
                end
                return nil;
        end;
        
        
        --
        -- getItemNameFromLink (link)
        --  
        --  retrieves an item name from a link or nil if it fails
        --  Thanks to Telo for providing me with the code!
        --
        getItemNameFromLink = function (link)
                local name;
                if( not link ) then
                        return nil;
                end
                for name in string.gfind(link, "|c%x+|Hitem:%d+:%d+:%d+:%d+|h%[(.-)%]|h|r") do
                        return name;
                end
                return nil;
        end;

        --
        -- isItemNotBindOnAnything (strings)
        --
        --  Checks if the item represented by the parameter is not bind on anything.
        --
        isItemNotBindOnAnything = function (strings)
                if ( not strings ) then
                        return false;
                end
                local tmpNumber = nil;
                local tmp = nil;
                for k, v in strings do
                        if ( ( v.left ) and ( string.find(v.left, DYNAMICDATA_BIND_ON) ) ) then
                                return true;
                        end
                end
                return false;
        end;
        
        --
        -- getDamage (strings)
        --
        --  Extracts damage info from an array that correspond to a tooltip.
        --
        getDamage = function (strings)
                if ( not strings ) then
                        return nil, nil;
                end
                local tmpNumber = nil;
                local tmp = nil;
                for k, v in strings do
                        if ( v.left )  then
                                local firstNumber = nil;
                                for tmp in string.gfind(v.left, "%w+") do 
                                        tmpNumber = tonumber(tmp);
                                        if ( tmpNumber ) then
                                                if ( firstNumber ) then
                                                        return firstNumber, tmpNumber;
                                                else
                                                        firstNumber = tmpNumber;
                                                end
                                        end
                                end
                        end
                end
                return nil, nil;
        end;

        --
        -- getItemStringType (strings)
        --
        --  Extracts item type information from an array that correspond to a tooltip.
        --
        getItemStringType = function (strings)
                if ( not strings ) then
                        return nil;
                end
                local str = nil;
                if ( ( strings[2] ) and ( strings[2].right ) ) then
                        str = strings[2].right;
                end
                if ( ( not str ) or ( strlen(str) <= 0 ) ) then
                        if ( ( strings[3] ) and ( strings[3].right ) ) then
                                str = strings[3].right;
                        end
                end
                if ( ( not str ) or ( strlen(str) <= 0 ) ) then
                        if ( ( strings[4] ) and ( strings[4].right ) ) then
                                str = strings[4].right;
                        end
                end
                return str;
        end;

        --
        -- extractWeaponSpeed (str)
        --
        --  Extracts weapon speed information from a string.
        --
        extractWeaponSpeed = function (str)
                local speed = -1;
                local tmp = str;
                local index = strfind(tmp, DYNAMICDATA_WEAPON_SPEED);
                if ( index ) then
                        tmp = strsub(tmp, index+1);
                        while ( strsub(tmp, 1, 1) == " " ) do
                                tmp = strsub(tmp, 2);
                        end
                        speed = tonumber(tmp);
                        if ( not speed ) then
                                speed = -1;
                        end
                end
                return speed;
        end;

        --
        -- getWeaponSpeed (strings)
        --
        --  Extracts weapon speed information from an array that correspond to a tooltip.
        --
        getWeaponSpeed = function (strings)
                if ( not strings ) then
                        return nil;
                end
                local str = "";
                if ( ( strings[2] ) and ( strings[2].right ) ) then
                        str = strings[2].right;
                end
                if ( strlen(str) <= 0 ) then
                        if ( ( strings[3] ) and ( strings[3].right ) ) then
                                str = strings[3].right;
                        end
                else
                end
                if ( strlen(str) <= 0 ) then
                        if ( ( strings[4] ) and ( strings[4].right ) ) then
                                str = strings[4].right;
                        end
                end
                local speed = DynamicData.util.extractWeaponSpeed(str);
                if ( speed <= 0 ) then
                        return nil;
                else
                        return speed;
                end
        end;

        --
        -- protectTooltipMoney ()
        --
        --  Thanks to Telo for providing this solution!
        --  Prevents the clearing of money from tooltips.
        --  USE WITH CAUTION! ALWAYS CALL unhookMoneyTooltip() AFTER SETTING THE TOOLTIP!
        --
        protectTooltipMoney = function()
                if ( not DynamicData.util.saved_GameTooltip_ClearMoney ) then
                        DynamicData.util.saved_GameTooltip_ClearMoney = GameTooltip_ClearMoney;
                        GameTooltip_ClearMoney = DynamicData.util.doNothing;
                end
        end;

        --
        -- unprotectTooltipMoney ()
        --
        --  Thanks to Telo for providing this solution!
        --  Allows the clearing of money from tooltips.
        --
        unprotectTooltipMoney = function()
                if ( DynamicData.util.saved_GameTooltip_ClearMoney ) then
                        GameTooltip_ClearMoney = DynamicData.util.saved_GameTooltip_ClearMoney;
                        DynamicData.util.saved_GameTooltip_ClearMoney = nil;
                end
        end;

        --
        -- scheduleFunction(when, function, [arguments])
        --
        --  schedules a function to occur in WHEN seconds.
        -- 
        scheduleFunction = function(when, func, ...)
                if ( not when ) then
                        return;
                end
                if ( not func ) then
                        return;
                end
                local scheduledFunction = {};
                scheduledFunction.time = when+GetTime();
                scheduledFunction.func = func;
                scheduledFunction.args = arg;
                DynamicData.util.addScheduledFunction(scheduledFunction);
        end;

        --
        -- scheduleNamedFunction(name, when, function, [arguments])
        --
        --  schedules a function to occur in WHEN seconds. Only one function with the same name will be scheduled.
        -- 
        scheduleNamedFunction = function(name, when, func, ...)
                if ( not name ) then
                        if ( arg ) then
                                return DynamicData.util.scheduleFunction(when, func, unpack(arg));
                        else
                                return DynamicData.util.scheduleFunction(when, func);
                        end
                end
                if ( not func ) then
                        return;
                end
                local scheduledFunction = {};
                scheduledFunction.name = name;
                scheduledFunction.time = when+GetTime();
                scheduledFunction.func = func;
                scheduledFunction.args = arg;
                local i;
                local size = table.getn(DynamicData.util.scheduledFunctions);
                local entry = nil;
                for i=1, size, 1 do
                        entry = DynamicData.util.scheduledFunctions[i];
                        if ( ( entry.name ) and ( entry.name == name ) ) then
                                table.remove(DynamicData.util.scheduledFunctions, i);
                                break;
                        end
                end
                DynamicData.util.addScheduledFunction(scheduledFunction);
        end;

        --
        -- scheduleAfterInitFunction (function, [args] )
        --
        --  schedules a function to be run after the init.
        --
        scheduleAfterInitFunction = function (func, ...) 
                local playerName = UnitName("player");
                if ( ( playerName ) and ( playerName ~= TEXT(UKNOWNBEING) ) and ( DynamicData.util.variablesHasBeenLoaded ) ) then
                        if ( arg ) then
                                func(unpack(arg));
                        else
                                func();
                        end
                else
                        if ( arg ) then
                                DynamicData.util.scheduleFunction(1, DynamicData.util.scheduleAfterInitFunction, func, unpack(arg));
                        else
                                DynamicData.util.scheduleFunction(1, DynamicData.util.scheduleAfterInitFunction, func);
                        end
                end
        end;
        
-- protected functions

        -- 
        -- postpone (params)
        --
        --  params.schedulingName = scheduling name
        --  params.func = function name
        --  params.args = function arguments
        --  params.lastPostponedName = name of the variable with last postponed information
        --  params.lastUpdatedName = name of the variable with last updated information
        --  params.minimumDelay = the smallest amount of time between function calls
        --
        postpone = function (params)
                local curTime = GetTime();
                if ( not params.minimumDelay ) then
                        params.minimumDelay = 0.1;
                end
                if ( not params.lastPostponedName ) then
                        params.lastPostponedName = params.schedulingName.."_lastPostponedName";
                end
                if ( not params.lastUpdatedName ) then
                        params.lastUpdatedName = params.schedulingName.."_lastUpdatedName";
                end
                setglobal(params.lastPostponedName, curTime);
                -- postpone checking until the updates have stopped
                if ( params.schedulingName ) then
                        UltimateUI_ScheduleByName(params.schedulingName, params.minimumDelay+0.01, DynamicData.util.handlePostponement, params);
                else
                        UltimateUI_Schedule(params.minimumDelay+0.01, DynamicData.util.handlePostponement, params);
                end
        end;


        -- 
        -- handlePostponement (params)
        --
        --  params.schedulingName = scheduling name
        --  params.func = function name
        --  params.args = function arguments
        --  params.lastPostponedName = name of the variable with last postponed information
        --  params.lastUpdatedName = name of the variable with last updated information
        --  params.minimumDelay = the smallest amount of time between function calls
        --
        handlePostponement = function (params)
                local curTime = GetTime();
                local lastPostponed = getglobal(params.lastPostponedName);
                local lastUpdated = getglobal(params.lastUpdatedName);
                if ( not lastPostponed ) then
                        lastPostponed = 0;
                end
                if ( not lastUpdated ) then
                        lastUpdated = 0;
                end
                if ( ( lastPostponed == 0 ) or ( curTime-lastPostponed <= params.minimumDelay ) and ( params.allowInitialUpdate == 1 ) ) then
                        postpone(params);
                        return;
                end
                if ( curTime-lastUpdated <= params.minimumDelay ) then
                        postpone(params);
                        return;
                end
                setglobal(params.lastPostponedName, 0);
                setglobal(params.lastUpdatedName, curTime);
                local f = params.func;
                if ( f ) then
                        if ( params.args ) then
                                f(unpack(params.args));
                        else
                                f();
                        end
                end
        end;
-- private functions    

        --
        -- addTooltipUsingFrame (frame)
        --
        --  Adds a frame to the list of frames that want tooltips to be untouched.
        --
        addTooltipUsingFrame = function(frame)
                if ( not frame ) then
                        return;
                end
                local frameName = nil;
                if ( type(frame) == "string" ) then
                        frameName = frame;
                else
                        frameName = frame:GetName();
                end
                if ( not frameName ) then
                        return;
                end
                for k, v in DynamicData.util.tooltipUsingFrames do
                        if ( v == frameName ) then
                                return;
                        end
                end
                table.insert(DynamicData.util.tooltipUsingFrames, frameName);
        end;


        --
        -- doNothing()
        --
        --  Does nothing.
        --
        doNothing = function()
        end;

        --
        -- handleScheduledFunctions(elapsed)
        --
        --  handles scheduled functions
        -- 
        handleScheduledFunctions = function(elapsed)
                local curTime = GetTime();
                local scheduledFunction = {};
                while ( ( DynamicData.util.scheduledFunctions[1] ) and ( DynamicData.util.scheduledFunctions[1].time <= curTime ) ) do
                        scheduledFunction = table.remove(DynamicData.util.scheduledFunctions, 1);
                        if ( scheduledFunction.args) then
                                scheduledFunction.func(unpack(scheduledFunction.args));
                        else
                                scheduledFunction.func();
                        end
                end
        end;
        
        --
        -- OnLoad()
        --
        --  sets up the util library. NOTE: This inserts an emulated UltimateUI_Schedule if not present.
        --
        OnLoad = function()
                local needHandler = false;
                if ( not UltimateUI_Schedule ) then
                        UltimateUI_Schedule = DynamicData.util.scheduleFunction;
                        needHandler = true;
                end
                if ( not UltimateUI_ScheduleByName ) then
                        UltimateUI_ScheduleByName = DynamicData.util.scheduleNamedFunction;
                        needHandler = true;
                end
                if ( not UltimateUI_AfterInit ) then
                        UltimateUI_AfterInit = DynamicData.util.scheduleAfterInitFunction;
                        needHandler = true;
                end
                if ( needHandler ) then
                        DynamicData.util.addOnTimeUpdateHandler(DynamicData.util.handleScheduledFunctions);
                end
        end;

        --
        -- addOnTimeUpdateHandler(func)
        --
        --  adds the func to the OnTime update handlers
        --
        addOnTimeUpdateHandler = function (func)
                DynamicData.util.addOnWhateverHandler(DynamicData.util.onUpdateHandlers, func);
        end;

        --
        -- removeOnTimeUpdateHandler(func)
        --
        --  removes the func from the OnTime update handlers
        --
        removeOnTimeUpdateHandler = function (func)
                DynamicData.util.removeOnWhateverHandler(DynamicData.util.onUpdateHandlers, func);
        end;

        --
        -- variablesLoaded()
        --
        --  run on VARIABLES_LOADED event
        --
        variablesLoaded = function ()
                variablesHasBeenLoaded = true;
        end;
        
        --
        -- addScheduledFunction(scheduledFunction)
        --
        --  schedules a function to occur sometime
        -- 
        addScheduledFunction = function(scheduledFunction)
                local i = 1;
                while ( ( DynamicData.util.scheduledFunctions[i] ) and ( DynamicData.util.scheduledFunctions[i].time < scheduledFunction.time ) ) do
                        i = i + 1;
                end
                table.insert(DynamicData.util.scheduledFunctions, i, scheduledFunction);
        end;

-- variables

        variablesHasBeenLoaded = false;

        scheduledFunctions = {};

        onUpdateHandlers = {};

        saved_GameTooltip_ClearMoney = nil;

        -- contains default frames which should prevent tooltips from being parsed.
        tooltipUsingFrames = {
                "TaxiFrame", "MerchantFrame", "TradeSkillFrame", 
                "SuggestFrame", "WhoFrame", "AuctionFrame", "MailFrame" 
        };

};