summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-addons/addons/temps
diff options
context:
space:
mode:
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/temps')
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/temps/ReadMe.md27
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/temps/items.lua52
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/temps/temps.lua345
3 files changed, 424 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/temps/ReadMe.md b/Data/BuiltIn/Libraries/lua-addons/addons/temps/ReadMe.md
new file mode 100644
index 0000000..9443371
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/temps/ReadMe.md
@@ -0,0 +1,27 @@
+**Author:** Snaps<br>
+**Version:** 1.0<br>
+**Date:** April 19th, 2017<br>
+
+# temps #
+
+* Makes buying temporary items and key items from escha npcs much easier.
+
+#### Commands: ####
+1. help - Shows a menu of commands in game
+2. buy [override] - Buys all temporary items in an escha zone.
+- buy - Buys all temporary items.
+- buy radialens - Buys all temporary items and also attempts to buy a radialens, even if it is on your blacklist or if you already have one.
+3. blacklist [add|a|remove|r] [item] - Add/Remove items from your blacklist.
+- blacklist add radialens - Adds radialens to your blacklist.
+- blacklist a "lucid potion i" - Adds Lucid Potion I to your blacklist.
+- blacklist remove radialens - Removes radialens from your blacklist.
+- blacklist r "lucid potion i" - Removes Lucid Potion I from your blacklist.
+4. turbo - Toggle the turbo feature.
+- turbo - Enables or disables the turbo feature.
+
+#### Notes: ####
+
+* You must be near an escha npc that sells temporary items.
+* A buy radialens command will refresh your Radialens duration in the event that you already have one.
+* The blacklist comes preloaded with Mollifier, Primeval Brew, and Radialens.
+
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/temps/items.lua b/Data/BuiltIn/Libraries/lua-addons/addons/temps/items.lua
new file mode 100644
index 0000000..06175f3
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/temps/items.lua
@@ -0,0 +1,52 @@
+return {
+ [2894] = {name="Tribulens", option=4, key_item=true, offset=0},
+ [3031] = {name="Radialens", option=2308, key_item=true, offset=9},
+ [3032] = {name="Mollifier", option=2564, key_item=true, offset=10},
+ [4182] = {name="Instant Reraise", option=7, key_item=false, offset=4},
+ [4202] = {name="Daedalus Wing", option=263, key_item=false, offset=26},
+ [4206] = {name="Catholicon", option=519, key_item=false, offset=14},
+ [4254] = {name="Megalixir", option=775, key_item=false, offset=12},
+ [5385] = {name="Barbarian's Drink", option=1031, key_item=false, offset=21},
+ [5386] = {name="Fighter's Drink", option=1287, key_item=false, offset=6},
+ [5387] = {name="Oracle's Drink", option=1543, key_item=false, offset=22},
+ [5388] = {name="Assassin's Drink", option=1799, key_item=false, offset=5},
+ [5389] = {name="Spy's Drink", option=2055, key_item=false, offset=8},
+ [5390] = {name="Braver's Drink", option=2311, key_item=false, offset=15},
+ [5391] = {name="Soldier's Drink", option=2567, key_item=false, offset=17},
+ [5392] = {name="Champion's Drink", option=2823, key_item=false, offset=9},
+ [5393] = {name="Monarch's Drink", option=3079, key_item=false, offset=20},
+ [5394] = {name="Gnostic's Drink", option=3335, key_item=false, offset=7},
+ [5395] = {name="Cleric's Drink", option=3591, key_item=false, offset=30},
+ [5397] = {name="Sprinter's Drink", option=3847, key_item=false, offset=16},
+ [5824] = {name="Lucid Potion I", option=4103, key_item=false, offset=0},
+ [5825] = {name="Lucid Potion II", option=4359, key_item=false, offset=10},
+ [5826] = {name="Lucid Potion III", option=4615, key_item=false, offset=23},
+ [5827] = {name="Lucid Ether I", option=4871, key_item=false, offset=1},
+ [5828] = {name="Lucid Ether II", option=5127, key_item=false, offset=11},
+ [5829] = {name="Lucid Ether III", option=5383, key_item=false, offset=24},
+ [5830] = {name="Lucid Elixir I", option=5639, key_item=false, offset=25},
+ [5834] = {name="Lucid Wings I", option=5895, key_item=false, offset=13},
+ [5835] = {name="Healing Salve I", option=6151, key_item=false, offset=2},
+ [5836] = {name="Healing Salve II", option=6407, key_item=false, offset=18},
+ [5837] = {name="Clear Salve I", option=6663, key_item=false, offset=3},
+ [5838] = {name="Clear Salve II", option=6919, key_item=false, offset=19},
+ [6399] = {name="Savior's Tonic", option=7175, key_item=false, offset=27},
+ [6400] = {name="Mirror's Tonic", option=7431, key_item=false, offset=28},
+ [6401] = {name="Moneta's Tonic", option=7687, key_item=false, offset=29},
+ [6402] = {name="Steadfast Tonic", option=7943, key_item=false, offset=31},
+ [5322] = {name="Healing Powder", option=8199, key_item=false, offset=32},
+ [4255] = {name="Mana Powder", option=8455, key_item=false, offset=33},
+ [4208] = {name="Catholicon +1", option=8711, key_item=false, offset=34},
+ [6474] = {name="Poison Buffer", option=8967, key_item=false, offset=35},
+ [5832] = {name="Healing Mist", option=9223, key_item=false, offset=36},
+ [5833] = {name="Mana Mist", option=9479, key_item=false, offset=37},
+ [5439] = {name="Vicar's Drink", option=9735, key_item=false, offset=38},
+ [5831] = {name="Lucid Elixir II", option=9991, key_item=false, offset=39},
+ [5436] = {name="Dusty Reraise", option=10247, key_item=false, offset=40},
+ [5853] = {name="Primeval Brew", option=10503, key_item=false, offset=41},
+ [6475] = {name="Lucid Wings II", option=10759, key_item=false, offset=42},
+ [6473] = {name="Super Revitalizer", option=11015, key_item=false, offset=43},
+ [6476] = {name="Virus Buffer", option=11271, key_item=false, offset=44},
+ [6477] = {name="Charm Buffer", option=11527, key_item=false, offset=45},
+ [6478] = {name="Curse Buffer", option=11783, key_item=false, offset=46},
+}
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/temps/temps.lua b/Data/BuiltIn/Libraries/lua-addons/addons/temps/temps.lua
new file mode 100644
index 0000000..1ec0f89
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/temps/temps.lua
@@ -0,0 +1,345 @@
+--[[
+temps v1.0
+
+Copyright © 2017, Mojo
+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 temps 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 Mojo 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 = 'temps'
+_addon.author = 'Mojo'
+_addon.version = '1.0'
+_addon.command = 'temps'
+
+require('chat')
+require('logger')
+require('pack')
+
+config = require('config')
+items = require('items')
+packets = require('packets')
+
+local help_text = [[
+temps - Command List:
+1. help - Displays this help menu.
+2. buy - Buys all temporary items in an escha zone.
+* buy - Buys all temporary items.
+* buy radialens - Buys all temporary items and also
+ attempts to buy a radialens, even if it is on your
+ blacklist or if you already have one.
+3. blacklist - Add(a)/Remove(r) items from your blacklist.
+* blacklist add radialens - Adds radialens to your
+ blacklist.
+* blacklist a radialens - Adds radialens to your blacklist.
+* blacklist remove radialens - Removes radialens from
+ your blacklist.
+* blacklist r radialens - Removes radialens from your
+ blacklist.
+4. turbo - Toggle the turbo feature.
+* turbo - Enables or disables the turbo feature.
+
+Notes:
+ You must be near an escha NPC that sells temporary
+ items. A buy radialens command will refresh your
+ radialens duration in the event that you already have
+ one.
+]]
+
+local defaults = {
+ turbo = false,
+ blacklist = S{
+ 'mollifier',
+ 'primeval brew',
+ 'radialens',
+ }
+}
+
+local settings = config.load('settings.xml', defaults)
+local handlers = {}
+local state = 'idle'
+local zone = nil
+local force = nil
+local silt = 0
+local key_ids = {}
+local key_items = 0
+local outstanding = 0
+local inflight = {}
+
+local temp_items = {
+ [1] = 0,
+ [2] = 0,
+}
+
+local conditions = {
+ temps = false,
+ busy = false,
+}
+
+local zones = {
+ [288] = {npc = "Affi", menu = 9701},
+ [289] = {npc = "Dremi", menu = 9701},
+ [291] = {npc = "Shiftrix", menu = 9701},
+}
+
+local function busy_wait(block, timeout, message)
+ local start = os.time()
+ while conditions[block] and ((os.time() - start) < timeout) do
+ coroutine.sleep(.1)
+ end
+ if os.time() - start >= timeout then
+ conditions[block] = false
+ return "timed out - %s":format(message)
+ end
+end
+
+local function validate(constrain)
+ zone = windower.ffxi.get_info()['zone']
+ if zones[zone] then
+ local npc = windower.ffxi.get_mob_by_name(zones[zone].npc)
+ if npc and ((math.sqrt(npc.distance) < 6) or (not constrain)) then
+ return npc
+ else
+ error("Too far from %s.":format(zones[zone].npc))
+ end
+ else
+ error("Not in an Escha zone.")
+ end
+end
+
+local function has_item(item)
+ if item.key_item then
+ return (math.floor(key_items/math.pow(2, item.offset)) % 2) == 1
+ else
+ return (math.floor(temp_items[math.floor(item.offset/32) + 1]/math.pow(2, item.offset % 32)) % 2) == 1
+ end
+end
+
+local function force_purchase(item)
+ return (item.name == force)
+end
+
+local function ignore_item(item)
+ return settings.blacklist:contains(item.name:lower())
+end
+
+local function purchase_items()
+ local npc = validate()
+ local count = 0
+ for item_id, item in pairs(items) do
+ if force_purchase(item) or (not has_item(item)) then
+ if ignore_item(item) and (not force_purchase(item)) then
+ windower.add_to_chat(100, string.format("Ignoring \30\2%s\30\43.", item.name))
+ else
+ local p = packets.new('outgoing', 0x5b, {
+ ["Target"] = npc.id,
+ ["Option Index"] = item.option,
+ ["Target Index"] = npc.index,
+ ["Automated Message"] = true,
+ ["Zone"] = zone,
+ ["Menu ID"] = zones[zone].menu,
+ })
+ windower.add_to_chat(100, string.format("Purchasing \30\2%s\30\43.", item.name))
+ packets.inject(p)
+ state = 'purchase'
+ inflight[item_id] = true
+ count = count + 1
+ if not settings.turbo then
+ coroutine.sleep(1)
+ end
+ end
+ end
+ end
+ if count == 0 then
+ windower.add_to_chat(100, "No temporary items to buy.")
+ else
+ outstanding = outstanding + count
+ if outstanding == 0 then
+ windower.add_to_chat(100, "Finished purchasing all temporary items.")
+ end
+ end
+end
+
+local function exit_menu(id, data, modified, injected, blocked)
+ if (id == 0x5b) and ((state == 'init') or (state == 'purchase')) then
+ local p = packets.parse('outgoing', data)
+ local npc = validate()
+ if (p['Target'] == npc.id) and not p['Automated Message'] then
+ outstanding = 0
+ state = 'idle'
+ end
+ end
+end
+
+local function observe_temps(id, data, modified, injected, blocked)
+ if (id == 0x5c) and conditions['temps'] then
+ local p = packets.parse('incoming', data)
+ temp_items[1] = p['Menu Parameters']:unpack('I', 1)
+ temp_items[2] = p['Menu Parameters']:unpack('I', 5)
+ conditions['temps'] = false
+ end
+end
+
+local function process_dialogue_event(id, data, modified, injected, blocked)
+ if (id == 0x34) and (state == 'init') then
+ local p = packets.parse('incoming', data)
+ state = 'purchase'
+ silt = p['Menu Parameters']:unpack('I', 5)
+ key_items = p['Menu Parameters']:unpack('I', 9)
+ conditions['temps'] = true
+ busy_wait('temps', 10, 'observe temp items')
+ purchase_items()
+ end
+end
+
+local function check_inflight(iid)
+ if (inflight[iid]) then
+ inflight[iid] = nil
+ outstanding = outstanding - 1
+ if outstanding == 0 then
+ windower.add_to_chat(100, "Finished purchasing all temporary items.")
+ end
+ end
+end
+
+local function receive_item(id, data, modified, injected, blocked)
+ if (id == 0x20) and (state == 'purchase') then
+ local p = packets.parse('incoming', data)
+ check_inflight(p['Item'])
+ end
+end
+
+local function obtained_key_item(p, item_id)
+ if (math.floor(item_id/512) == p['Type']) then
+ local bit = item_id % 512
+ local n = bit % 8
+ local character = math.floor(bit/8) + 1
+ return ((math.floor(p['Key item available']:byte(character)/math.pow(2, n)) % 2) == 1)
+ else
+ return false
+ end
+end
+
+local function receive_key_items(id, data, modified, injected, blocked)
+ if (id == 0x55) and (state == 'purchase') then
+ local p = packets.parse('incoming', data)
+ for k, v in pairs(inflight) do
+ if obtained_key_item(p, k) then
+ check_inflight(k)
+ end
+ end
+ end
+end
+
+local function validate_item(item)
+ for k, v in pairs(items) do
+ if item:lower() == v.name:lower() then
+ return v.name
+ end
+ end
+ error("%s not found in items list.":format(item))
+end
+
+local function start(override)
+ if not (state == 'idle') then
+ return error("Addon is busy.")
+ elseif override then
+ force = validate_item(override)
+ if not force then
+ return
+ else
+ notice("Override provided for %s.":format(force))
+ end
+ else
+ force = nil
+ end
+ local npc = validate(true)
+ if npc then
+ local p = packets.new('outgoing', 0x01a, {
+ ["Target"] = npc.id,
+ ["Target Index"] = npc.index,
+ })
+ packets.inject(p)
+ state = 'init'
+ else
+ state = 'idle'
+ end
+end
+
+local function help()
+ windower.add_to_chat(100, help_text)
+end
+
+local function blacklist(cmd, name)
+ if not cmd then
+ return error("No blacklist command provided.")
+ elseif not S{'add', 'a', 'remove', 'r'}:contains(cmd) then
+ return error("Unknown blacklist command %s.":format(cmd))
+ elseif not name then
+ return error("No blacklist command parameter provided.")
+ end
+ local item = validate_item(name)
+ if not item then
+ return
+ elseif S{'add', 'a'}:contains(cmd) then
+ notice("Adding %s to your blacklist.":format(item))
+ settings.blacklist:add(item:lower())
+ else
+ notice("Removing %s from your blacklist.":format(item))
+ settings.blacklist:remove(item:lower())
+ end
+ settings:save()
+end
+
+local function turbo()
+ if settings.turbo then
+ notice("Disabling turbo.")
+ settings.turbo = false
+ else
+ notice("Enabling turbo.")
+ settings.turbo = true
+ end
+ settings:save()
+end
+
+local function handle_command(cmd, ...)
+ local cmd = cmd and cmd:lower() or 'help'
+ if handlers[cmd] then
+ handlers[cmd](...)
+ else
+ error("Unknown command %s.":format(cmd))
+ end
+end
+
+handlers['buy'] = start
+handlers['help'] = help
+handlers['blacklist'] = blacklist
+handlers['turbo'] = turbo
+
+windower.register_event('incoming chunk', process_dialogue_event)
+windower.register_event('incoming chunk', receive_item)
+windower.register_event('incoming chunk', receive_key_items)
+windower.register_event('incoming chunk', observe_temps)
+windower.register_event('outgoing chunk', exit_menu)
+windower.register_event('addon command', handle_command)