lotrointerface.com
Search Downloads

LoTROInterface SVN SequenceBars

[/] [trunk/] [Thurallor/] [Common/] [Utils/] [Watcher.lua] - Rev 43

Go to most recent revision | Compare with Previous | Blame | View Log

-- Singleton object for efficiently observing and keeping track of game state,
-- providing convenient functions and events.

local Watcher = {};
Thurallor.Utils.Watcher = Watcher;

local function DoSave()
--Puts("Saving...");
    -- Workaround for Turbine localization bug.
    local saveData = ExportTable(Watcher.settings);
    Turbine.PluginData.Save(Turbine.DataScope.Account, "Thurallor_GameInfo", saveData, function()
--Puts("Save complete.");
    end);
end

local startupTime = Turbine.Engine.GetGameTime();
local function SaveSettings()
    if (not Watcher.settingsLoaded) then
        if (Turbine.Engine.GetGameTime() - startupTime > 5) then
            -- Settings file probably doesn't exist if it hasn't loaded in 5 seconds.
            Watcher.settingsLoaded = true;
        else
            return;
        end
    end
    
    -- Do the save operation at the next Update; thus aggregating multiple consecutive save requests.
    if (not Watcher.saveRequested) then
        Watcher.saveRequested = true;
        Watcher.window:SetWantsUpdates(true);
    end
end

local function DoDelayedCallback(_time, event, args)
    if (not Watcher.delayedCallbacks) then
        Watcher.delayedCallbacks = {};
    end
    table.insert(Watcher.delayedCallbacks, { time = _time, event = event, args = args } );
    Watcher.window:SetWantsUpdates(true);
end

local function AddActorEffect(effectsObject, effect)
    local categories, name = effect:GetCategory(), effect:GetName();
    if (not effectsObject.cache[name]) then
        effectsObject.cache[name] = 0;
    end
    effectsObject.cache[name] = effectsObject.cache[name] + 1;

    if (not Watcher.settings.knownEffects[name]) then
        -- This is an effect we have never seen before.  Learn some info about it and save for future reference.
        categories = effect:GetCategory();
        Watcher.settings.knownEffects[name] = {
            categories, effect:GetIcon(), effect:IsCurable(), effect:IsDebuff()};

        local bits = categories;
        if (not Watcher.AddCategories[bits]) then
            -- This is a GetCategory value we have never seen before.  Create functions for adding/removing.
            local AddCategories = "local categories = ...; ";
            local RemoveCategories = "local categories = ...; ";
            if (bits >= 2048) then
                -- Unknown bits; discard them.
                bits = bits % 2048;
            end
            if (bits >= 1226) then
                -- Turbine.Gameplay.EffectCategory.Dispellable is the OR of several bits
                AddCategories = AddCategories .. "categories[1226] = categories[1226] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[1226] = categories[1226] - 1; ";
            end
            if (bits >= 1024) then
                AddCategories = AddCategories .. "categories[1024] = categories[1024] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[1024] = categories[1024] - 1; ";
                bits = bits - 1024;
            end
            if (bits >= 512) then
                AddCategories = AddCategories .. "categories[512] = categories[512] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[512] = categories[512] - 1; ";
                bits = bits - 512;
            end
            if (bits >= 256) then
                AddCategories = AddCategories .. "categories[256] = categories[256] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[256] = categories[256] - 1; ";
                bits = bits - 256;
            end
            if (bits >= 128) then
                AddCategories = AddCategories .. "categories[128] = categories[128] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[128] = categories[128] - 1; ";
                bits = bits - 128;
            end
            if (bits >= 64) then
                AddCategories = AddCategories .. "categories[64] = categories[64] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[64] = categories[64] - 1; ";
                bits = bits - 64;
            end
            if (bits >= 32) then
                AddCategories = AddCategories .. "categories[32] = categories[32] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[32] = categories[32] - 1; ";
                bits = bits - 32;
            end
            if (bits >= 16) then
                AddCategories = AddCategories .. "categories[16] = categories[16] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[16] = categories[16] - 1; ";
                bits = bits - 16;
            end
            if (bits >= 8) then
                AddCategories = AddCategories .. "categories[8] = categories[8] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[8] = categories[8] - 1; ";
                bits = bits - 8;
            end
            if (bits >= 4) then
                AddCategories = AddCategories .. "categories[4] = categories[4] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[4] = categories[4] - 1; ";
                bits = bits - 4;
            end
            if (bits >= 2) then
                AddCategories = AddCategories .. "categories[2] = categories[2] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[2] = categories[2] - 1; ";
                bits = bits - 2;
            end
            if (bits >= 1) then
                AddCategories = AddCategories .. "categories[1] = categories[1] + 1; ";
                RemoveCategories = RemoveCategories .. "categories[1] = categories[1] - 1; ";
            end
            
            Watcher.settings.funcs.AddCategories[categories] = AddCategories;
            Watcher.AddCategories[categories] = loadstring(AddCategories);
            Watcher.settings.funcs.RemoveCategories[categories] = RemoveCategories;
            Watcher.RemoveCategories[categories] = loadstring(RemoveCategories);
        end

        SaveSettings();
    else
        categories = Watcher.settings.knownEffects[name][1];
    end

    Watcher.AddCategories[categories](effectsObject.activeCategories);
end

local function RemoveActorEffect(effectsObject, effect)
    local categories, name = effect:GetCategory(), effect:GetName();
    Watcher.RemoveCategories[categories](effectsObject.activeCategories);
    effectsObject.cache[name] = effectsObject.cache[name] - 1;
    if (effectsObject.cache[name] == 0) then
        effectsObject.cache[name] = nil;
    end
end

local function GetActorEffects(effectsObject)
    effectsObject.cache = {};
    effectsObject.activeCategories = {
        [Turbine.Gameplay.EffectCategory.Dispellable] = 0;
        [Turbine.Gameplay.EffectCategory.Corruption] = 0;
        [Turbine.Gameplay.EffectCategory.Elemental] = 0;
        [Turbine.Gameplay.EffectCategory.Tactical] = 0;
        [Turbine.Gameplay.EffectCategory.Poison] = 0;
        [Turbine.Gameplay.EffectCategory.Fear] = 0;
        [Turbine.Gameplay.EffectCategory.Song] = 0;
        [Turbine.Gameplay.EffectCategory.Cry] = 0;
        [Turbine.Gameplay.EffectCategory.Wound] = 0;
        [Turbine.Gameplay.EffectCategory.Physical] = 0;
        [Turbine.Gameplay.EffectCategory.Disease] = 0;
        [1] = 0;
    };
    for e = 1, effectsObject:GetCount(), 1 do
        local effect = effectsObject:Get(e);
        AddActorEffect(effectsObject, effect);
    end
end

local function GetEquipment()
    local eq = Watcher.playerEquipmentObject;
    eq.cache = { byName = {}; bySlot = {}; };
    for slot = 1, eq:GetSize() do
        local item = eq:GetItem(slot);
        if (item) then
            local name = item:GetItemInfo():GetName();
            eq.cache.byName[name] = { item, slot };
            eq.cache.bySlot[slot] = { item, name };
        end
    end
end

local function GetBackpack()
    local bp = Watcher.playerBackpackObject;
    bp.cache = { byName = {}; bySlot = {}; };
    for slot = 1, bp:GetSize() do
        local item = bp:GetItem(slot);
        if (item) then
            local name = item:GetItemInfo():GetName();
            if (not bp.cache.byName[name]) then
                bp.cache.byName[name] = { slot };
            else
                table.insert(bp.cache.byName[name], slot);
            end
            bp.cache.bySlot[slot] = { item, name };
        end
    end
end

local function ResetTimeChanged(skill, args)
    DoCallbacks(self, "ResetTimeChanged", args);
end

local function GetSkills(skills)
    skills.cache = { names = {}; byName = {}; byIcon = {} };
    local cache = skills.cache;
    for c = 1, skills:GetCount(), 1 do
        local skill = skills:GetItem(c);
--        AddCallback(skill, "ResetTimeChanged", ResetTimeChanged);
        local skillInfo = skill:GetSkillInfo();
        local icon = skillInfo:GetIconImageID();
        local name = skillInfo:GetName();
        cache.byName[name] = skill;
        cache.byIcon[icon] = skill;
        table.insert(cache.names, name);
    end
    table.sort(cache.names);
    return skills.cache;
end

local function GetGambits()
    local gambits = Watcher.playerTrainedGambits;
    gambits.cache = { names = {}; byName = {}; byIcon = {} };
    if (Watcher.playerObject:GetClass() == Turbine.Gameplay.Class.Warden) then
        for c = 1, gambits:GetCount(), 1 do
            local skill = gambits:GetItem(c);
            local skillInfo = skill:GetSkillInfo();
            local icon = skillInfo:GetIconImageID();
            local name = skillInfo:GetName();
            gambits.cache.byName[name] = skill;
            gambits.cache.byIcon[icon] = skill;
        end
    end
    return gambits.cache;
end

local function GetParty()
    local party = Watcher.playerPartyObject;
    party.cache = { byName = {}; };
    for c = 1, party:GetMemberCount(), 1 do
        local member = party:GetMember(c);
        local name = member:GetName();
        party.cache.byName[name] = member;
    end
    return party.cache;
end

local function PlayerEffectAdded(effectsObject, args)
    local effect = effectsObject:Get(args.Index);
    AddActorEffect(effectsObject, effect);
    DoCallbacks(Watcher, "PlayerEffectAdded", effect);
end

local function PlayerEffectRemoved(effectsObject, args)
    RemoveActorEffect(effectsObject, args.Effect);
    DoCallbacks(Watcher, "PlayerEffectRemoved", args.Effect);
end

local function PlayerEffectsCleared(effectsObject, args)
    GetActorEffects(effectsObject);
    DoCallbacks(Watcher, "PlayerEffectsCleared", args);
end

local function TargetEffectAdded(effectsObject, args)
    local effect = effectsObject:Get(args.Index);
    AddActorEffect(effectsObject, effect);
    DoCallbacks(Watcher, "TargetEffectAdded", effect);
end

function TargetEffectRemoved(effectsObject, args)
    RemoveActorEffect(effectsObject, args.Effect);
    DoCallbacks(Watcher, "TargetEffectRemoved", args.Effect);
end

local function TargetEffectsCleared(effectsObject, args)
    GetActorEffects(effectsObject);
    DoCallbacks(Watcher, "TargetEffectsCleared", args);
end

local function PlayerPartyChanged(sender, args)
    Watcher.playerPartyObject = Watcher.playerObject:GetParty();
    if (Watcher.playerPartyObject) then
        AddCallback(Watcher.playerPartyObject, "MemberAdded", PartyMemberAdded);
        AddCallback(Watcher.playerPartyObject, "MemberRemoved", PartyMemberRemoved);
        GetParty();
    end
end

local function UpdatePlayerTarget()
    -- Bug workaround:
    -- If the target is a member of the player's party, GetEffects() won't work
    -- unless we use the Party object to get the Player object.
    if (Watcher.targetObject and Watcher.playerPartyObject) then
        local name = Watcher.targetObject:GetName();
        local member = Watcher.playerPartyObject.cache.byName[name];
        if (member) then
            Watcher.targetObject = member;
        end
    end

    -- Need to get the effects object now so it can start observing effects.
-- Target effects currently are too buggy to use.    
--[[
    if (Watcher.targetObject and Watcher.targetObject.GetEffects) then
        Watcher.targetEffectsObject = Watcher.targetObject:GetEffects();
    end
]]

    DoCallbacks(Watcher, "PlayerTargetChanged", Watcher.targetObject);
end

local function PlayerTargetChanged()
    Watcher.targetObject = Watcher.playerObject:GetTarget();
    Watcher.targetEffectsObject = nil;

    -- Client may not immediately have information about the target.  When
    -- the info arrives, we'll get a BaseMaxPowerChanged event, which seems
    -- to occur near the end of the burst of events that will arrive.
    if (Watcher.targetObject and Watcher.targetObject.GetBaseMaxPower and (Watcher.targetObject.GetBaseMaxPower() == 0)) then
        Watcher.targetObject.BaseMaxPowerChanged = function()
            Watcher.targetObject.BaseMaxPowerChanged = nil;
            Watcher.targetObject = Watcher.playerObject:GetTarget();
            Watcher.targetEffectsObject = nil;
            UpdatePlayerTarget();
        end
    end
    
    UpdatePlayerTarget();
end

local function ItemEquipped(sender, args)
--Puts("ItemEquipped: args = " .. Serialize(args));    
    local slot, item, name = args.Index, args.Item, args.Item:GetItemInfo():GetName();
    Watcher.playerEquipmentObject.cache.byName[name] = { item, slot };
    Watcher.playerEquipmentObject.cache.bySlot[slot] = { item, name };
    DoCallbacks(Watcher, "ItemEquipped", args);
end

local function ItemUnequipped(sender, args)
--Puts("ItemUnequipped: args = " .. Serialize(args));    
    local slot, name = args.Index, args.Item:GetItemInfo():GetName();
    Watcher.playerEquipmentObject.cache.bySlot[slot] = nil;
    Watcher.playerEquipmentObject.cache.byName[name] = nil;
    DoCallbacks(Watcher, "ItemUnequipped", args);
end

local function ItemAdded(sender, args)
--Puts("ItemAdded: args = " .. Serialize(args));    
    -- occurs out-of-combat; efficiency not important
    GetBackpack();
end

local function ItemRemoved(sender, args)
--Puts("ItemRemoved: args = " .. Serialize(args));    
    -- occurs out-of-combat; efficiency not important
    GetBackpack();
end

local function ItemMoved(sender, args)
    -- occurs out-of-combat; efficiency not important
    GetBackpack();
    DoCallbacks(Watcher, "ItemMoved", args);
end

local function BackpackSizeChanged(sender, args)
    -- rare occurrence, out-of-combat; efficiency not important
    GetBackpack();
end

local function ChatReceived(sender, args)
    if (args.ChatType == Turbine.ChatType.Advancement) then
        if (string.match(args.Message, Watcher.SkillsChangedStr)) then
            -- Trait line changed.  Reread skills lists.
            Watcher.playerTrainedSkills.cache = nil;
            Watcher.playerUntrainedSkills.cache = nil;
        elseif (string.match(args.Message, Watcher.TraitTreeChangedStr)) then
            DoDelayedCallback(Turbine.Engine.GetGameTime() + 1.5, "TraitTreeChanged", args);
        end
    end
end

local function SkillAdded(sender, args)
    -- rare occurrence, out-of-combat; efficiency not important
    GetSkills(Watcher.playerTrainedSkills);
    GetSkills(Watcher.playerUntrainedSkills);
end

local function SkillRemoved(sender, args)
    -- rare occurrence, out-of-combat; efficiency not important
    GetSkills(Watcher.playerTrainedSkills);
    GetSkills(Watcher.playerUntrainedSkills);
end

local function PartyMemberAdded(sender, args)
    -- rare occurrence, out-of-combat; efficiency not important
    GetParty();
end

local function PartyMemberRemoved(sender, args)
    -- rare occurrence, out-of-combat; efficiency not important
    GetParty();
end

local function InCombatChanged()
        local inCombat = Watcher.playerObject:IsInCombat();
    if (inCombat) then
                collectgarbage("stop");
    else
                collectgarbage("restart");
    end
        DoCallbacks(Watcher, "InCombatChanged", { InCombat = inCombat });
end

local function LoadSettings()
--Puts("Loading...");
    Turbine.PluginData.Load(Turbine.DataScope.Account, "Thurallor_GameInfo", function(loadData, args)
        if (not loadData) then
            return;
        end
        
        -- Workaround for Turbine localization bug.
        local settings = ImportTable(loadData);
        if (not settings) then
            return;
        end
        
        -- Previously-saved settings override the defaults
        DeepTableCopy(settings, Watcher.settings);
        
        -- Compile loaded functions
        for categories, sourceCode in pairs(settings.funcs.AddCategories) do
            Watcher.AddCategories[categories] = loadstring(sourceCode);
        end
        for categories, sourceCode in pairs(settings.funcs.RemoveCategories) do
            Watcher.RemoveCategories[categories] = loadstring(sourceCode);
        end
        
        -- Lua API bug workaround: Target effects object will not contain valid
        -- data until a few ticks after plugin load.
        if (Watcher.targetEffectsObject) then
            Watcher.targetEffectsObject.cache = nil;
        end
        
        -- Allow save operations to proceed.
        Watcher.settingsLoaded = true;
        SaveSettings();
--Puts("Load complete.");
    end);
end

function Watcher.GetTrainedSkillsInfo()
    local cache = Watcher.playerTrainedSkills.cache;
    if (not cache) then
        cache = GetSkills(Watcher.playerTrainedSkills);
    end
    return cache;
end

function Watcher.GetUntrainedSkillsInfo()
    local cache = Watcher.playerUntrainedSkills.cache;
    if (not cache) then
        cache = GetSkills(Watcher.playerUntrainedSkills);
    end
    return cache;
end

function Watcher.GetSkillsInfo(trainedSkillsFirst)
    local trainedSkillsCache = Watcher.GetTrainedSkillsInfo();
    local untrainedSkillsCache = Watcher.GetUntrainedSkillsInfo();
    if (#untrainedSkillsCache.names > 0) then
        local cache = { names = {}; byName = {}; byIcon = {} };
        for c in values({ trainedSkillsCache, untrainedSkillsCache }) do
            for k, v in pairs(c.byIcon) do
                cache.byIcon[k] = v;
            end
            for k, v in pairs(c.byName) do
                cache.byName[k] = v;
            end
            for k, v in pairs(c.names) do
                table.insert(cache.names, v);
            end
        end
        if (not trainedSkillsFirst) then
            table.sort(cache.names);
        end
        return cache;
    else
        return trainedSkillsCache;
    end
end

function Watcher.GetGambitsInfo()
    local cache = Watcher.playerTrainedGambits.cache;
    if (not cache) then
        cache = GetGambits();
    end
    for name in sorted_keys(cache.byName) do
        table.insert(cache.names, name);
    end
    return cache;
end

function Watcher.GetKnownEffectNames()
    local names = {};
    for name in sorted_keys(Watcher.settings.knownEffects) do
        table.insert(names, name);
    end
    return names;
end

-- If itemName is specified, the equipped item (if any) with the specified name is returned.
-- If itemSlot is specified, the equipped item (if any) at the specified slot is returned.
-- If neither is specified, a random equipped item (if any) is returned.
-- Returns slot, item (or nil).
function Watcher.GetEquippedItem(itemName, itemSlot)
    if ((not itemSlot) and (not itemName)) then
        for name, byName in pairs(Watcher.playerEquipmentObject.cache.byName) do
            local item, slot = unpack(byName);
            return slot, item;
        end
    elseif (not itemSlot) then
        local byName = Watcher.playerEquipmentObject.cache.byName[itemName];
        if (byName) then
            local item, slot = unpack(byName);
            return slot, item;
        end
    elseif (not itemName) then
        local bySlot = Watcher.playerEquipmentObject.cache.bySlot[itemSlot];
        if (bySlot) then
            local item, name = unpack(bySlot);
            return itemSlot, item;
        end
    else -- itemName and itemSlot specified
        local bySlot = Watcher.playerEquipmentObject.cache.bySlot[itemSlot];
        if (bySlot) then
            local item, name = unpack(bySlot);
            if (name == itemName) then
                return itemSlot, item;
            end
        end
    end
end

function Watcher.GetItemQuantity(itemName)
    local quantity = 0;
    local slots = Watcher.playerBackpackObject.cache.byName[itemName];
    if (slots) then
        for i, s in pairs(slots) do
            local item = Watcher.playerBackpackObject:GetItem(s);
            if (item) then
                quantity = quantity + item:GetQuantity();
            end
        end
    end
    return quantity;
end

-- Can accept either an iconID (number) or a skill name (string).
function Watcher.SkillReady(arg)
    local cache = Watcher.playerTrainedSkills.cache;
    if (not cache) then
        cache = GetSkills(Watcher.playerTrainedSkills);
    end
    if (type(arg) == "string") then
        skill = cache.byName[arg];
    elseif (type(arg) == "number") then
        skill = cache.byIcon[arg];
    end
--    return (skill and skill:IsUsable() and (skill:GetResetTime() == -1));
    return (skill and (skill:GetResetTime() == -1));
end

-- Can accept either an iconID (number) or a skill name (string).
function Watcher.SkillTrained(arg)
    local cache, skill = Watcher.playerTrainedSkills.cache;
    if (not cache) then
        cache = GetSkills(Watcher.playerTrainedSkills);
    end
    if (type(arg) == "string") then
        skill = cache.byName[arg];
    elseif (type(arg) == "number") then
        skill = cache.byIcon[arg];
    end
    return (skill ~= nil);
end

local function PlayerHasEffectCategory(category)
    if (category) then
        return Watcher.playerEffectsObject.activeCategories[category] > 0;
    end
end

function Watcher.PlayerHasEffectCategory(category)
    -- Start watching player effects.
    Watcher.playerEffectsObject = Watcher.playerObject:GetEffects();
    AddCallback(Watcher.playerEffectsObject, "EffectAdded", PlayerEffectAdded);
    AddCallback(Watcher.playerEffectsObject, "EffectRemoved", PlayerEffectRemoved);
    AddCallback(Watcher.playerEffectsObject, "EffectsCleared", PlayerEffectsCleared);
    GetActorEffects(Watcher.playerEffectsObject);
    
    -- Next time this function is called, we don't need to do the above again.
    Watcher.PlayerHasEffectCategory = PlayerHasEffectCategory;
    Watcher.PlayerHasEffect = PlayerHasEffect;
    
    return PlayerHasEffectCategory(category);
end

local function PlayerHasEffect(name)
    if (name) then
        return Watcher.playerEffectsObject.cache[name];
    end
end

function Watcher.PlayerHasEffect(name)
    -- Start watching player effects.
    Watcher.playerEffectsObject = Watcher.playerObject:GetEffects();
    AddCallback(Watcher.playerEffectsObject, "EffectAdded", PlayerEffectAdded);
    AddCallback(Watcher.playerEffectsObject, "EffectRemoved", PlayerEffectRemoved);
    AddCallback(Watcher.playerEffectsObject, "EffectsCleared", PlayerEffectsCleared);
    GetActorEffects(Watcher.playerEffectsObject);
    
    -- Next time this function is called, we don't need to do the above again.
    Watcher.PlayerHasEffectCategory = PlayerHasEffectCategory;
    Watcher.PlayerHasEffect = PlayerHasEffect;

    return PlayerHasEffect(name);
end

function Watcher.TargetHasEffectCategory(category)

    -- Target effects tracking is so buggy as to be useless.  Hoping Turbine addresses this bug soon.
    if (true) then
        return false;
    end

    if (not Watcher.targetEffectsObject) then
        -- No target, or target isn't one whose effects can be read.
        return false;
    end
    if (not Watcher.targetEffectsObject.cache) then
        -- Bug workaround: Since EffectRemoved event never fires for target
        -- effects, we must reread the list every time it is queried.
        GetActorEffects(Watcher.targetEffectsObject);
        Watcher.window:SetWantsUpdates(true); -- to delete the cache at next Update cycle
    end
    return Watcher.targetEffectsObject.activeCategories[category] > 0;
end

function Watcher.TargetHasEffect(name)

    -- Target effects tracking is so buggy as to be useless.  Hoping Turbine addresses this bug soon.
    if (true) then
        return false;
    end

    if (not Watcher.targetEffectsObject) then
        -- No target, or target isn't one whose effects can be read.
        return false;
    end
    if (not Watcher.targetEffectsObject.cache) then
        -- Bug workaround: Since EffectRemoved event never fires for target
        -- effects, we must reread the list every time it is queried.
        GetActorEffects(Watcher.targetEffectsObject);
        Watcher.window:SetWantsUpdates(true); -- to delete the cache at next Update cycle
    end
    return Watcher.targetEffectsObject.cache[name];
end

local function Constructor()
    
    -- Default settings
    Watcher.settings = {};
    Watcher.settings.knownEffects = {};
    Watcher.settings.funcs = {};
    Watcher.settings.funcs.AddCategories = {};
    Watcher.settings.funcs.RemoveCategories = {};

    -- Optimized functions generated on-the-fly
    Watcher.AddCategories = {};
    Watcher.RemoveCategories = {};
    
    -- Object for monitoring display updates:
    Watcher.window = Turbine.UI.Window();
    function Watcher.window:Update()
        self:SetWantsUpdates(false);
        if (Watcher.saveRequested) then
            DoSave();
            Watcher.saveRequested = false;
        end
        if (Watcher.targetEffectsObject) then
            Watcher.targetEffectsObject.cache = nil;
        end
        if (Watcher.delayedCallbacks) then
            local notyet = {};
            for k, v in pairs(Watcher.delayedCallbacks) do
                if (Turbine.Engine.GetGameTime() >= v.time) then
                    DoCallbacks(Watcher, v.event, v.args);
                else
                    table.insert(notyet, v);
                end
            end
            Watcher.delayedCallbacks = nil;
            if (#notyet > 0) then
                Watcher.delayedCallbacks = notyet;
            self:SetWantsUpdates(true);
            end
        end
    end
    
    -- Object for monitoring player events
    Watcher.playerObject = Turbine.Gameplay.LocalPlayer:GetInstance();
    AddCallback(Watcher.playerObject, "InCombatChanged", InCombatChanged);
    AddCallback(Watcher.playerObject, "PartyChanged", PlayerPartyChanged);
    AddCallback(Watcher.playerObject, "TargetChanged", PlayerTargetChanged);
    PlayerPartyChanged();
    PlayerTargetChanged();
    
    Watcher.playerEquipmentObject = Watcher.playerObject:GetEquipment();
    AddCallback(Watcher.playerEquipmentObject, "ItemEquipped", ItemEquipped);
    AddCallback(Watcher.playerEquipmentObject, "ItemUnequipped", ItemUnequipped);
    GetEquipment();

    Watcher.playerBackpackObject = Watcher.playerObject:GetBackpack();
    AddCallback(Watcher.playerBackpackObject, "ItemAdded", ItemAdded);
    AddCallback(Watcher.playerBackpackObject, "ItemRemoved", ItemRemoved);
    AddCallback(Watcher.playerBackpackObject, "ItemMoved", ItemMoved);
    AddCallback(Watcher.playerBackpackObject, "SizeChanged", BackpackSizeChanged);
    GetBackpack();
    
    Watcher.playerTrainedSkills = Watcher.playerObject:GetTrainedSkills();
    AddCallback(Watcher.playerTrainedSkills, "SkillAdded", PlayerSkillAdded);
    AddCallback(Watcher.playerTrainedSkills, "SkillRemoved", PlayerSkillRemoved);
    GetSkills(Watcher.playerTrainedSkills);
    
    Watcher.playerUntrainedSkills = Watcher.playerObject:GetUntrainedSkills();
    GetSkills(Watcher.playerUntrainedSkills);
    
    Watcher.playerClassAttributes = Watcher.playerObject:GetClassAttributes();
    if (Watcher.playerObject:GetClass() == Turbine.Gameplay.Class.Warden) then
        Watcher.playerTrainedGambits = Watcher.playerClassAttributes:GetTrainedGambits();
    else
        Watcher.playerTrainedGambits = {};
    end
    
    -- For monitoring chat messages
    AddCallback(Turbine.Chat, "Received", ChatReceived);
    local language = Turbine.Engine:GetLanguage();
    if ((language == Turbine.Language.EnglishGB) or (language == Turbine.Language.English)) then
        Watcher.SkillsChangedStr = "^You have acquired the .* skill%.";
        Watcher.TraitTreeChangedStr = "^You have acquired the Class Specialization Bonus Trait";
    elseif (language == Turbine.Language.German) then
        Watcher.SkillsChangedStr = "^Ihr habt Euch die Fertigkeit .* angeeignet%.";
        Watcher.TraitTreeChangedStr = "^Ihr habt diese Bonus-Eigenschaft für Klassenspezialisierung erlangt";
    elseif (language == Turbine.Language.French) then
        Watcher.SkillsChangedStr = "^Vous avez acquis la compétence .*%.";
        Watcher.TraitTreeChangedStr = "^Vous avez obtenu le trait bonus de spécialisation de classe";
    end
end


-- Create single instance and load saved settings (if any).
Constructor();
LoadSettings();


--t = Turbine.UI.Window();
--t:SetVisible(true);
--t:SetBackColor(Turbine.UI.Color.Red);
--t:SetMouseVisible(true);
--function t:MouseClick()
--    Puts("cache = " .. PrettyPrint(Watcher.playerEffectsObject.cache, ""));
--end

Go to most recent revision | Compare with Previous | Blame


All times are GMT -5. The time now is 04:18 AM.


Our Network
EQInterface | EQ2Interface | Minion | WoWInterface | ESOUI | LoTROInterface | MMOUI | Swtorui