-
Notifications
You must be signed in to change notification settings - Fork 452
New addon - EmpyPopTracker #1822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,326 @@ | ||
| --[[ | ||
| Copyright © 2020, Dean James (Xurion of Bismarck) | ||
| 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 Empy Pop Tracker 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 Dean James (Xurion of Bismarck) 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 = 'Empy Pop Tracker' | ||
| _addon.author = 'Dean James (Xurion of Bismarck)' | ||
| _addon.commands = { 'ept', 'empypoptracker' } | ||
| _addon.version = '2.0.0' | ||
|
|
||
| config = require('config') | ||
| res = require('resources') | ||
| nm_data = require('nms/index') | ||
|
|
||
| active = false | ||
|
|
||
| local EmpyPopTracker = {} | ||
|
|
||
| local defaults = {} | ||
| defaults.text = {} | ||
| defaults.text.pos = {} | ||
| defaults.text.pos.x = 0 | ||
| defaults.text.pos.y = 0 | ||
| defaults.text.bg = {} | ||
| defaults.text.bg.alpha = 150 | ||
| defaults.text.bg.blue = 0 | ||
| defaults.text.bg.green = 0 | ||
| defaults.text.bg.red = 0 | ||
| defaults.text.bg.visible = true | ||
| defaults.text.padding = 8 | ||
| defaults.text.text = {} | ||
| defaults.text.text.font = 'Consolas' | ||
| defaults.text.text.size = 10 | ||
| defaults.tracking = 'briareus' | ||
| defaults.visible = true | ||
| defaults.add_to_chat_mode = 8 | ||
|
|
||
| EmpyPopTracker.settings = config.load(defaults) | ||
| EmpyPopTracker.text = require('texts').new(EmpyPopTracker.settings.text, EmpyPopTracker.settings) | ||
|
|
||
| colors = {} | ||
| colors.success = '\\cs(100,255,100)' | ||
| colors.danger = '\\cs(255,50,50)' | ||
| colors.warning = '\\cs(255,170,0)' | ||
| colors.close = '\\cr' | ||
|
|
||
| function owns_item(id, items) | ||
| for _, bag in ipairs(items) do | ||
| for _, item in ipairs(bag) do | ||
| if item.id == id then | ||
| return true | ||
| end | ||
| end | ||
| end | ||
|
|
||
| return false | ||
| end | ||
|
|
||
| function owns_key_item(id, items) | ||
| local owned = false | ||
|
|
||
| for _, item_id in pairs(items) do | ||
| if item_id == id then | ||
| owned = true | ||
| break | ||
| end | ||
| end | ||
|
|
||
| return owned | ||
| end | ||
|
|
||
| function item_treasure_pool_count(id, treasure) | ||
| local count = 0 | ||
|
|
||
| for _, item in pairs(treasure) do | ||
| if item.item_id == id then | ||
| count = count + 1 | ||
| end | ||
| end | ||
|
|
||
| return count | ||
| end | ||
|
|
||
| function ucwords(str) | ||
| local result = string.gsub(str, '(%a)([%w_\']*)', function(first, rest) | ||
| return first:upper() .. rest:lower() | ||
| end) | ||
|
|
||
| return result | ||
| end | ||
|
|
||
| function get_indent(depth) | ||
| return string.rep(' ', depth) | ||
| end | ||
|
|
||
| function generate_text(data, key_items, items, depth) | ||
| local text = depth == 1 and data.name or '' | ||
| for _, pop in pairs(data.pops) do | ||
| local resource | ||
| local item_scope | ||
| local owns_pop | ||
| local in_pool_count = 0 | ||
| local item_identifier = '' | ||
|
|
||
| if pop.type == 'key item' then | ||
| resource = res.key_items[pop.id] | ||
| owns_pop = owns_key_item(pop.id, key_items) | ||
| item_identifier = 'Ж ' | ||
| else | ||
| resource = res.items[pop.id] | ||
| owns_pop = owns_item(pop.id, items) | ||
| in_pool_count = item_treasure_pool_count(pop.id, items.treasure) | ||
| end | ||
|
|
||
| local pop_name = 'Unknown pop' | ||
| if resource then | ||
| pop_name = ucwords(resource.name) | ||
| end | ||
|
|
||
| --separator line for each top-level mob | ||
| if depth == 1 then | ||
| text = text .. '\n' | ||
| end | ||
|
|
||
| local item_colour | ||
| if owns_pop then | ||
| item_colour = colors.success | ||
| else | ||
| item_colour = colors.danger | ||
| end | ||
|
|
||
| local pool_notification = '' | ||
| if in_pool_count > 0 then | ||
| pool_notification = colors.warning .. ' [' .. in_pool_count .. ']' .. colors.close | ||
| end | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to display that even if the count is zero? I'm not sure, up to you.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I originally had this showing for each item. I decided to only show it when there's one in the pool as it was difficult to identify them at a glance, plus it acts as a kind of alert due to the amber colour. |
||
| text = text .. '\n' .. get_indent(depth) .. pop.dropped_from.name .. '\n' .. get_indent(depth) .. ' >> ' .. item_colour .. item_identifier .. pop_name .. colors.close .. pool_notification | ||
| if pop.dropped_from.pops then | ||
| text = text .. generate_text(pop.dropped_from, key_items, items, depth + 1) | ||
| end | ||
| end | ||
|
|
||
| return text | ||
| end | ||
|
|
||
| EmpyPopTracker.generate_info = function(nm, key_items, items) | ||
| local info = { | ||
| has_all_kis = true, | ||
| text = '' | ||
| } | ||
|
|
||
| if nm.pops then | ||
| for _, key_item_data in pairs(nm.pops) do | ||
| local has_pop_ki = owns_key_item(key_item_data.id, key_items) | ||
|
|
||
| if not has_pop_ki then | ||
| info.has_all_kis = false | ||
| end | ||
| end | ||
| end | ||
|
|
||
| info.text = generate_text(nm, key_items, items, 1) | ||
|
|
||
| return info | ||
| end | ||
|
|
||
| function find_nms(pattern) | ||
| local matching_nms = {} | ||
| local lower_pattern = pattern:lower() | ||
| for _, nm in pairs(nm_data) do | ||
| local nm_name = nm.name:lower() | ||
| local result = windower.wc_match(nm_name, lower_pattern) | ||
| if result then | ||
| table.insert(matching_nms, nm_name) | ||
| end | ||
| end | ||
|
|
||
| return matching_nms | ||
| end | ||
|
|
||
| windower.register_event('addon command', function(command, ...) | ||
| command = command and command:lower() or 'help' | ||
|
|
||
| if commands[command] then | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will crash the addon if a user just types windower.register_event('addon command', function(command, ...)
command = command and command:lower() or 'help'
-- command checking here
end)This way you protect against invalid usage and default to
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking about it, in your case you could just do: windower.register_event('addon command', function(command, ...)
(command and commands[command:lower()] or commands.help)(...)
end)Though not sure how readable that still is :D
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't creating unreadable code great for job security? XD I ran
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, looks like I derped here. It does indeed return
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've made it consistent with other addons now. I've simplified the first few lines of the addon command event. |
||
| commands[command](...) | ||
| else | ||
| commands.help() | ||
| end | ||
| end) | ||
|
|
||
| commands = {} | ||
|
|
||
| commands.track = function(...) | ||
| local args = {...} | ||
| local nm_search_pattern = args[1] | ||
| local matching_nm_names = find_nms(nm_search_pattern) | ||
|
|
||
| if #matching_nm_names == 0 then | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, 'Unable to find a NM using: "' .. nm_search_pattern .. '"') | ||
| elseif #matching_nm_names > 1 then | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '"' .. nm_search_pattern .. '" matches ' .. #matching_nm_names .. ' NMs. Please be more explicit:') | ||
| for key, matching_file_name in pairs(matching_nm_names) do | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, ' Match ' .. key .. ': ' .. ucwords(matching_file_name)) | ||
| end | ||
| else | ||
| active = true | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, 'Now tracking: ' .. ucwords(matching_nm_names[1])) | ||
| EmpyPopTracker.settings.tracking = matching_nm_names[1] | ||
| EmpyPopTracker.update() | ||
| commands.show() | ||
| end | ||
| end | ||
| commands.t = commands.track | ||
|
|
||
| commands.hide = function() | ||
| active = false | ||
| EmpyPopTracker.text:visible(false) | ||
| EmpyPopTracker.settings.visible = false | ||
| EmpyPopTracker.settings:save() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should not need to modify the settings at all when doing this. It should adjust them and save accordingly. Does that not happen for you? Same in the function below.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I originally expected this to just work like some of my other addons that use texts and settings. I just checked and it doesn't save it automatically :/ I had just assumed the texts visible setting wasn't saved like the others?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm you are right, I just checked and visibility is not automatically saved. I wonder why I did it like that... I guess I did not consider visibility as a user based setting and instead wanted the addon to control that behavior. An argument I no longer agree with, but I think that's what influenced my decision back then. |
||
| end | ||
|
|
||
| commands.show = function() | ||
| active = true | ||
| EmpyPopTracker.text:visible(true) | ||
| EmpyPopTracker.settings.visible = true | ||
| EmpyPopTracker.settings:save() | ||
| EmpyPopTracker.update() | ||
| end | ||
|
|
||
| commands.help = function() | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '---Empy Pop Tracker---') | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, 'Available commands:') | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '//ept track briareus - tracks Briareus pops (search patterns such as apadem* work too!)') | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '//ept hide - hides the UI') | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '//ept show - shows the UI') | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '//ept list - lists all trackable NMs') | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '//ept help - displays this help') | ||
| end | ||
|
|
||
| commands.list = function() | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '---Empy Pop Tracker---') | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, 'Trackable NMs:') | ||
| for _, nm in pairs(nm_data) do | ||
| windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, ucwords(nm.name)) | ||
| end | ||
| end | ||
|
|
||
| commands.bg = function() | ||
| local tracking_nm = nm_data[EmpyPopTracker.settings.tracking] | ||
| local url = 'https://www.bg-wiki.com/bg/' .. tracking_nm.name | ||
| windower.open_url(url) | ||
| end | ||
|
|
||
| EmpyPopTracker.update = function() | ||
| local key_items = windower.ffxi.get_key_items() | ||
| local items = windower.ffxi.get_items() | ||
| local tracked_nm_data = nm_data[EmpyPopTracker.settings.tracking] | ||
| local generated_info = EmpyPopTracker.generate_info(tracked_nm_data, key_items, items) | ||
| EmpyPopTracker.text:text(generated_info.text) | ||
| if generated_info.has_all_kis then | ||
| EmpyPopTracker.text:bg_color(0, 75, 0) | ||
| else | ||
| EmpyPopTracker.text:bg_color(0, 0, 0) | ||
| end | ||
| if EmpyPopTracker.settings.visible then | ||
| EmpyPopTracker.text:visible(true) | ||
| end | ||
| end | ||
|
|
||
| windower.register_event('load', function() | ||
| if windower.ffxi.get_info().logged_in and EmpyPopTracker.settings.visible then | ||
| active = true | ||
| EmpyPopTracker.update() | ||
| end | ||
| end) | ||
|
|
||
| windower.register_event('add item', 'remove item', function() | ||
| if active then | ||
| EmpyPopTracker.update() | ||
| end | ||
| end) | ||
|
|
||
| windower.register_event('incoming chunk', function(id) | ||
| --0x055: KI update | ||
| --0x0D2: Treasure pool addition | ||
| --0x0D3: Treasure pool lot/drop | ||
| if active and id == 0x055 or id == 0x0D2 or id == 0x0D3 then | ||
| EmpyPopTracker.update() | ||
| end | ||
| end) | ||
|
|
||
| windower.register_event('login', function() | ||
| if EmpyPopTracker.settings.visible then | ||
| EmpyPopTracker.text:visible(true) | ||
| active = true | ||
| end | ||
| end) | ||
|
|
||
| windower.register_event('logout', function() | ||
| EmpyPopTracker.text:visible(false) | ||
| active = false | ||
| end) | ||
|
|
||
| return EmpyPopTracker | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # FFXI Empyrean Pop Tracker | ||
|
|
||
| An FFXI Windower 4 addon that tracks items and key items for popping Empyrean NMs in Abyssea, such as Briareus, Apademak and Sobek. | ||
|
|
||
|   | ||
|
|
||
| Key items are identified by the Zhe (Ж) character. Treasure pool counts for pop items are listed in amber after the item in the format of [3] (assuming 3 of that item in the pool). | ||
|
|
||
| ## Load | ||
|
|
||
| `//lua load empypoptracker` | ||
|
|
||
| ## Track an NM | ||
|
|
||
| `//ept track glavoid` tracks Glavoid pop items/key items. | ||
|
|
||
| You can also track an NM by using a wildcard pattern, because fuck having to remember how to spell Itzpapalotl: | ||
|
|
||
| `//ept track itz*` | ||
|
|
||
| For a full list of trackable NMs, see the nms directory or use the `list` command (see below). | ||
|
|
||
| ## Other Commands | ||
|
|
||
| ### List Trackable NMs | ||
|
|
||
| `//ept list` | ||
|
|
||
| ### Open BG Wiki for NM | ||
|
|
||
| `//ept bg` | ||
|
|
||
| ### Hide UI | ||
|
|
||
| `//ept hide` | ||
|
|
||
| ### Show UI | ||
|
|
||
| `//ept show` | ||
|
|
||
| ### Display Help | ||
|
|
||
| `//ept help` | ||
|
|
||
| ## Where is Fistule? | ||
|
|
||
| Fistule is a unique NM when compared to the others. It does not require KIs that can be tracked, so it isn't included with the addon. | ||
|
|
||
| ## Contributing | ||
|
|
||
| Notice something not quite right? [Raise an issue](https://github.com/xurion/ffxi-empy-pop-tracker/issues). | ||
|
|
||
| [Pull requests](https://github.com/xurion/ffxi-empy-pop-tracker/pulls) welcome! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While there's no issue here it would perform better to iterate each bag individually and would be easier to read, plus you can make it immune to breakage due to new bags being added, as it will automatically work when we update LuaCore:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Future proof ftw