diff options
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/Debuffed')
| -rw-r--r-- | Data/BuiltIn/Libraries/lua-addons/addons/Debuffed/Debuffed.lua | 305 | ||||
| -rw-r--r-- | Data/BuiltIn/Libraries/lua-addons/addons/Debuffed/README.md | 38 | 
2 files changed, 343 insertions, 0 deletions
| diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/Debuffed/Debuffed.lua b/Data/BuiltIn/Libraries/lua-addons/addons/Debuffed/Debuffed.lua new file mode 100644 index 0000000..d3c177e --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-addons/addons/Debuffed/Debuffed.lua @@ -0,0 +1,305 @@ +--[[ +Copyright © 2019, Xathe +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +    * Redistributions of source code must retain the above copyright +    notice, this list of conditions and the following disclaimer. +    * Redistributions in binary form must reproduce the above copyright +    notice, this list of conditions and the following disclaimer in the +    documentation and/or other materials provided with the distribution. +    * Neither the name of Debuffed nor the +    names of its contributors may be used to endorse or promote products +    derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Xathe BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +]] + +_addon.name = 'Debuffed' +_addon.author = 'Xathe (Asura)' +_addon.version = '1.0.0.4' +_addon.commands = {'dbf','debuffed'} + +config = require('config') +packets = require('packets') +res = require('resources') +texts = require('texts') +require('logger') + +defaults = {} +defaults.interval = .1 +defaults.mode = 'blacklist' +defaults.timers = true +defaults.hide_below_zero = false +defaults.whitelist = S{} +defaults.blacklist = S{} +defaults.colors = {} +defaults.colors.player = {} +defaults.colors.player.red = 255 +defaults.colors.player.green = 255 +defaults.colors.player.blue = 255 +defaults.colors.others = {} +defaults.colors.others.red = 255 +defaults.colors.others.green = 255 +defaults.colors.others.blue = 0 + +settings = config.load(defaults) +box = texts.new('${current_string}', settings) +box:show() + +list_commands = T{ +    w = 'whitelist', +    wlist = 'whitelist', +    white = 'whitelist', +    whitelist = 'whitelist', +    b = 'blacklist', +    blist = 'blacklist', +    black = 'blacklist', +    blacklist = 'blacklist' +} + +sort_commands = T{ +    a = 'add', +    add = 'add', +    ['+'] = 'add', +    r = 'remove', +    remove = 'remove', +    ['-'] = 'remove' +} + +player_id = 0 +frame_time = 0 +debuffed_mobs = {} + +function update_box() +    local lines = L{} +    local target = windower.ffxi.get_mob_by_target('t') +     +    if target and target.valid_target and (target.claim_id ~= 0 or target.spawn_type == 16) then +        local data = debuffed_mobs[target.id] +         +        if data then +            for effect, spell in pairs(data) do +                local name = res.spells[spell.id].name +                local remains = math.max(0, spell.timer - os.clock()) +                 +                if settings.mode == 'whitelist' and settings.whitelist:contains(name) or settings.mode == 'blacklist' and not settings.blacklist:contains(name) then +                    if settings.timers and remains > 0 then +                        lines:append('\\cs(%s)%s: %.0f\\cr':format(get_color(spell.actor), name, remains)) +                    elseif remains < 0 and settings.hide_below_zero then +                        debuffed_mobs[target.id][effect] = nil +                    else +                        lines:append('\\cs(%s)%s\\cr':format(get_color(spell.actor), name)) +                    end +                end +            end +        end +    end +     +    if lines:length() == 0 then +        box.current_string = '' +    else +        box.current_string = 'Debuffed [' .. target.name .. ']\n\n' .. lines:concat('\n') +    end +end + +function get_color(actor) +    if actor == player_id then +        return '%s,%s,%s':format(settings.colors.player.red, settings.colors.player.green, settings.colors.player.blue) +    else +        return '%s,%s,%s':format(settings.colors.others.red, settings.colors.others.green, settings.colors.others.blue) +    end +end + +function handle_overwrites(target, new, t) +    if not debuffed_mobs[target] then +        return true +    end +     +    for effect, spell in pairs(debuffed_mobs[target]) do +        local old = res.spells[spell.id].overwrites or {} +         +        -- Check if there isn't a higher priority debuff active +        if table.length(old) > 0 then +            for _,v in ipairs(old) do +                if new == v then +                    return false +                end +            end +        end +         +        -- Check if a lower priority debuff is being overwritten +        if table.length(t) > 0 then +            for _,v in ipairs(t) do +                if spell.id == v then +                    debuffed_mobs[target][effect] = nil +                end +            end +        end +    end +    return true +end + +function apply_debuff(target, effect, spell, actor) +    if not debuffed_mobs[target] then +        debuffed_mobs[target] = {} +    end +     +    -- Check overwrite conditions +    local overwrites = res.spells[spell].overwrites or {} +    if not handle_overwrites(target, spell, overwrites) then +        return +    end +     +    -- Create timer +    debuffed_mobs[target][effect] = {id=spell, timer=(os.clock() + (res.spells[spell].duration or 0)), actor=actor} +end + +function handle_shot(target) +    if not debuffed_mobs[target] or not debuffed_mobs[target][134] then +        return true +    end +     +    local current = debuffed_mobs[target][134].id +    if current < 26 then +        debuffed_mobs[target][134].id = current + 1 +    end +end + +function inc_action(act) +    if act.category ~= 4 then +        if act.category == 6 and act.param == 131 then +            handle_shot(act.targets[1].id) +        end +        return +    end +     +    -- Damaging spells +    if S{2,252}:contains(act.targets[1].actions[1].message) then +        local target = act.targets[1].id +        local spell = act.param +        local effect = res.spells[spell].status +        local actor = act.actor_id + +        if effect then +            apply_debuff(target, effect, spell, actor) +        end +         +    -- Non-damaging spells +    elseif S{236,237,268,271}:contains(act.targets[1].actions[1].message) then +        local target = act.targets[1].id +        local effect = act.targets[1].actions[1].param +        local spell = act.param +        local actor = act.actor_id +         +        if res.spells[spell].status and res.spells[spell].status == effect then +            apply_debuff(target, effect, spell, actor) +        end +    end +end + +function inc_action_message(arr) + +    -- Unit died +    if S{6,20,113,406,605,646}:contains(arr.message_id) then +        debuffed_mobs[arr.target_id] = nil +         +    -- Debuff expired +    elseif S{64,204,206,350,531}:contains(arr.message_id) then +        if debuffed_mobs[arr.target_id] then +            debuffed_mobs[arr.target_id][arr.param_1] = nil +        end +    end +end + +windower.register_event('login','load', function() +    player_id = (windower.ffxi.get_player() or {}).id +end) + +windower.register_event('logout','zone change', function() +    debuffed_mobs = {} +end) + +windower.register_event('incoming chunk', function(id, data) +    if id == 0x028 then +        inc_action(windower.packets.parse_action(data)) +    elseif id == 0x029 then +        local arr = {} +        arr.target_id = data:unpack('I',0x09) +        arr.param_1 = data:unpack('I',0x0D) +        arr.message_id = data:unpack('H',0x19)%32768 +         +        inc_action_message(arr) +    end +end) + +windower.register_event('prerender', function() +    local curr = os.clock() +    if curr > frame_time + settings.interval then +        frame_time = curr +        update_box() +    end +end) + +windower.register_event('addon command', function(command1, command2, ...) +    local args = L{...} +    command1 = command1 and command1:lower() or nil +    command2 = command2 and command2:lower() or nil +     +    local name = args:concat(' ') +    if command1 == 'm' or command1 == 'mode' then +        if settings.mode == 'blacklist' then +            settings.mode = 'whitelist' +        else +            settings.mode = 'blacklist' +        end +        log('Changed to %s mode.':format(settings.mode)) +        settings:save() +    elseif command1 == 't' or command1 == 'timers' then +        settings.timers = not settings.timers +        log('Timer display %s.':format(settings.timers and 'enabled' or 'disabled')) +        settings:save() +    elseif command1 == 'i' or command1 == 'interval' then +        settings.interval = tonumber(command2) or .1 +        log('Refresh interval set to %s seconds.':format(settings.interval)) +        settings:save() +    elseif command1 == 'h' or command1 == 'hide' then +        settings.hide_below_zero = not settings.hide_below_zero +        log('Timers that reach 0 will be %s.':format(settings.hide_below_zero and 'hidden' or 'shown')) +        settings:save() +    elseif list_commands:containskey(command1) then +        if sort_commands:containskey(command2) then +            local spell = res.spells:with('name', windower.wc_match-{name}) +            command1 = list_commands[command1] +            command2 = sort_commands[command2] +             +            if spell == nil then +                error('No spells found that match: %s':format(name)) +            elseif command2 == 'add' then +                settings[command1]:add(spell.name) +                log('Added spell to %s: %s':format(command1, spell.name)) +            else +                settings[command1]:remove(spell.name) +                log('Removed spell from %s: %s':format(command1, spell.name)) +            end +            settings:save() +        end +    else +        print('%s (v%s)':format(_addon.name, _addon.version)) +        print('    \\cs(255,255,255)mode\\cr - Switches between blacklist and whitelist mode (default: blacklist)') +        print('    \\cs(255,255,255)timers\\cr - Toggles display of debuff timers (default: true)') +        print('    \\cs(255,255,255)interval <value>\\cr - Allows you to change the refresh interval (default: 0.1)') +        print('    \\cs(255,255,255)blacklist|whitelist add|remove <name>\\cr - Adds or removes the spell <name> to the specified list') +    end +end) diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/Debuffed/README.md b/Data/BuiltIn/Libraries/lua-addons/addons/Debuffed/README.md new file mode 100644 index 0000000..ae986b1 --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-addons/addons/Debuffed/README.md @@ -0,0 +1,38 @@ +# Debuffed + +An addon that tracks and displays debuffs on your current target. Filters are available to customise which debuffs are shown. + +### Commands + +`//debuffed mode` + +This will switch between blacklist and whitelist mode for debuff filtering. + +`//debuffed timers` + +This toggles the display of timers for debuffs. + +`//debuffed interval <value>` + +This allows you to adjust the refresh interval for the textbox. It will be updated every \<value\> number of seconds. + +`//debuffed hide` + +This toggles the automatic removal of effects when their timer reaches zero. + +`//debuffed blacklist|whitelist add|remove <name>` + +This adds or removes the spell \<name\> to the specified filter. + +### Abbreviations + +The following abbreviations are available for addon commands: +* `debuffed` to `dbf` +* `mode` to `m` +* `timers` to `t` +* `interval` to `i` +* `hide` to `h` +* `blacklist` to `b` or `blist` or `black` +* `whitelist` to `w` or `wlist` or `white` +* `add` to `a` or `+` +* `remove` to `r` or `-` | 
