diff options
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/roe')
-rw-r--r-- | Data/BuiltIn/Libraries/lua-addons/addons/roe/ReadMe.md | 26 | ||||
-rw-r--r-- | Data/BuiltIn/Libraries/lua-addons/addons/roe/roe.lua | 302 |
2 files changed, 328 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/roe/ReadMe.md b/Data/BuiltIn/Libraries/lua-addons/addons/roe/ReadMe.md new file mode 100644 index 0000000..a3e3dc2 --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-addons/addons/roe/ReadMe.md @@ -0,0 +1,26 @@ +**Author:** Cair<br> +**Version:** 1.0<br> +**Date:** Oct. 30, 2017<br> + +### ROE ### + +This addon lets you save your currently set objectives to profiles that can be loaded. It can also be configured to remove quests for you. By default, ROE will remove quests that are not in a profile only if their progress is zero. You can customize this to your liking. + + + +#### Commands: #### +1. help - Displays this help menu. +2. save <profile name> : saves the currently set ROE to the named profile +3. set <profile name> : attempts to set the ROE objectives in the profile + - Objectives may be canceled automatically based on settings. + - The default setting is to only cancel ROE that have 0 progress if space is needed +4. unset <profile name> : removes currently set objectives + - if a profile name is specified, every objective in that profile will be removed + - if a profile name is not specificed, all objectives will be removed (based on your settings) +5. settings <settings name> : toggles the specified setting + * settings: + * clear : removes objectives if space is needed (default true) + * clearprogress : remove objectives even if they have non-zero progress (default false) + * clearall : clears every objective before setting new ones (default false) +6. blacklist [add|remove] <id> : blacklists a quest from ever being removed + - I do not currently have a mapping of quest IDs to names diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/roe/roe.lua b/Data/BuiltIn/Libraries/lua-addons/addons/roe/roe.lua new file mode 100644 index 0000000..49dd52d --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-addons/addons/roe/roe.lua @@ -0,0 +1,302 @@ +-- Copyright © 2017, Cair +-- 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 ROE 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 Cair 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 = {} +_addon.name = 'ROE' +_addon.version = '1.1' +_addon.author = "Cair" +_addon.commands = {'roe'} + +packets = require('packets') +config = require('config') +require('logger') + + +local defaults = T{ + profiles = T{ + default = S{}, + }, + blacklist = S{}, + clear = true, + clearprogress = false, + clearall = false, +} + +settings = config.load(defaults) + +_roe = T{ + active = T{}, + complete = T{}, + max_count = 30, +} + + +local function cancel_roe(id) + id = tonumber(id) + + if not id then return end + + if settings.blacklist[id] or not _roe.active[id] then return end + + local p = packets.new('outgoing', 0x10d, {['RoE Quest'] = id }) + packets.inject(p) +end + +local function accept_roe(id) + id = tonumber(id) + + if not id or _roe.complete[id] or _roe.active[id] then return end + if id and id >= 4008 and id <= 4021 then return end + + local p = packets.new('outgoing', 0x10c, {['RoE Quest'] = id }) + packets.inject(p) +end + +local function eval(...) + assert(loadstring(table.concat({...}, ' ')))() +end + +local function save(name) + if not type(name) == "string" then + error('`save` : specify a profile name') + return + end + + name = name:lower() + + settings.profiles[name] = S(_roe.active:keyset()) + settings:save('global') + notice('saved %d objectives to the profile %s':format(_roe.active:length(), name)) +end + + +local function list() + notice('You have saved the following profiles: ') + notice(settings.profiles:keyset()) +end + +local function set(name) + if not type(name) == "string" then + error('`set` : specify a profile name') + return + end + + name = name:lower() + + if not settings.profiles[name] then + error('`set` : the profile \'%s\' does not exist':format(name)) + return + end + + local needed_quests = settings.profiles[name]:diff(_roe.active:keyset()) + local available_slots = _roe.max_count - _roe.active:length() + local to_remove = S{} + + if settings.clearall then + to_remove:update(_roe.active:keyset()) + elseif settings.clear then + for id,progress in pairs(_roe.active) do + if (needed_quests:length() - to_remove:length()) <= available_slots then + break + end + if (progress == 0 or settings.clearprogress) and not settings.blacklist[id] then + to_remove:add(id) + end + end + end + + + if (needed_quests:length() - to_remove:length()) > available_slots then + error('you do not have enough available quest slots') + return + end + + for id in to_remove:it() do + cancel_roe(id) + coroutine.sleep(.5) + end + + for id in needed_quests:it() do + accept_roe(id) + coroutine.sleep(.5) + end + + notice('loaded the profile \'%s\'':format(name)) + +end + +local function unset(name) + + name = name and name:lower() + + if name and settings.profiles[name] then + for id in _roe.active:keyset():intersection(settings.profiles[name]):it() do + cancel_roe(id) + coroutine.sleep(.5) + end + notice('unset the profile \'%s\'':format(name)) + elseif name then + error('`unset` : the profile \'%s\' does not exist':format(name)) + elseif not name then + notice('clearing ROE objectives.') + for id,progress in pairs(_roe.active:copy()) do + if progress == 0 or settings.clearprogress then + cancel_roe(id) + coroutine.sleep(.5) + end + end + end + +end + +local true_strings = S{'true','t','y','yes','on'} +local false_strings = S{'false','f','n','no','off'} +local bool_strings = true_strings:union(false_strings) + +local function handle_setting(setting,val) + setting = setting and setting:lower() or setting + val = val and val:lower() or val + + if not setting or not settings:containskey(setting) then + error('specified setting (%s) does not exist':format(setting or '')) + elseif type(settings[setting]) == "boolean" then + if not val or not bool_strings:contains(val) then + settings[setting] = not settings[setting] + elseif true_strings:contains(val) then + settings[setting] = true + else + settings[setting] = false + end + + notice('%s setting is now %s':format(setting, tostring(settings[setting]))) + end + +end + +local function blacklist(add_remove,id) + add_remove = add_remove and add_remove:lower() + id = id and tonumber(id) + + + if add_remove and id then + if add_remove == 'add' then + settings.blacklist:add(id) + notice('roe quest %d added to the blacklist':format(id)) + elseif add_remove == 'remove' then + if id >= 4008 and id <= 4021 then + return + else + settings.blacklist:remove(id) + notice('roe quest %d removed from the blacklist':format(id)) + end + else + error('`blacklist` specify \'add\' or \'remove\'') + end + else + error('`blacklist` requires two args, [add|remove] <quest id>') + end + +end + + +local function help() + notice([[ROE - Command List: +1. help - Displays this help menu. +2. save <profile name> : saves the currently set ROE to the named profile +3. set <profile name> : attempts to set the ROE objectives in the profile + - Objectives may be canceled automatically based on settings. + - The default setting is to only cancel ROE that have 0 progress if space is needed +4. unset : removes currently set objectives + - By default, this will only remove objectives without progress made +5. settings <settings name> : toggles the specified setting + * settings: + * clear : removes objectives if space is needed (default true) + * clearprogress : remove objectives even if they have non-zero progress (default false) + * clearall : clears every objective before setting new ones (default false) +6. blacklist [add|remove] <id> : blacklists a quest from ever being removed + - I do not currently have a mapping of quest IDs to names]]) +end + +local cmd_handlers = { + eval = eval, + save = save, + list = list, + set = set, + unset = unset, + settings = handle_setting, + blacklist = blacklist, + help = help, +} + + +local function inc_chunk_handler(id,data) + if id == 0x111 then + _roe.active:clear() + for i = 1, _roe.max_count do + local offset = 5 + ((i - 1) * 4) + local id,progress = data:unpack('b12b20', offset) + if id > 0 then + _roe.active[id] = progress + end + end + elseif id == 0x112 then + local complete = T{data:unpack('b1':rep(1024),4)}:key_map( + function(k) + return (k + 1024*data:unpack('H', 133) - 1) + end):map( + function(v) + return (v == 1) + end) + _roe.complete:update(complete) + end +end + +local function addon_command_handler(command,...) + local cmd = command and command:lower() or "help" + if cmd_handlers[cmd] then + cmd_handlers[cmd](...) + else + error('unknown command `%s`':format(cmd or '')) + end + +end + +local function load_handler() + for k,v in pairs(settings.profiles) do + if type(v) == "string" then + settings.profiles[k] = S(v:split(','):map(tonumber)) + end + end + + local last_roe = windower.packets.last_incoming(0x111) + if last_roe then inc_chunk_handler(0x111,last_roe) end + +end + +windower.register_event('incoming chunk', inc_chunk_handler) +windower.register_event('addon command', addon_command_handler) +windower.register_event('load', load_handler) |