summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/addons/addons/craft/craft.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Data/BuiltIn/Libraries/addons/addons/craft/craft.lua')
-rw-r--r--Data/BuiltIn/Libraries/addons/addons/craft/craft.lua814
1 files changed, 0 insertions, 814 deletions
diff --git a/Data/BuiltIn/Libraries/addons/addons/craft/craft.lua b/Data/BuiltIn/Libraries/addons/addons/craft/craft.lua
deleted file mode 100644
index 9751dd7..0000000
--- a/Data/BuiltIn/Libraries/addons/addons/craft/craft.lua
+++ /dev/null
@@ -1,814 +0,0 @@
---[[
-Craft v1.1.3
-
-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 craft 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 = 'craft'
-_addon.author = 'Mojo, Recipes provided by BG-Wiki.com'
-_addon.version = '1.1.3'
-_addon.commands = {'craft'}
-
-require('chat')
-require('lists')
-require('coroutine')
-require('queues')
-require('logger')
-require('tables')
-require('sets')
-require('strings')
-
-local packets = require('packets')
-local res = require('resources')
-local recipes = require('recipes')
-local queue = Q{}
-local handlers = {}
-local delay = 24
-local synth = 0
-local skip_delay = false
-local busy = false
-local paused = false
-local display = false
-local jiggle = false
-local support = false
-local zone = nil
-local hqsynth = false
-
-local conditions = {
- move = false,
- sort = false,
- crystal = false,
- support = false,
-}
-
-local food = false
-local supported = false
-local appropriated = {}
-local inventory = {}
-
-local function filter_bag(v)
- return not (v.name:match("Inventory") or
- v.name:match("Temporary") or
- v.name:match("Wardrobe"))
-end
-
-local function get_bag_command(k)
- return res.bags[k].command
-end
-
-local function get_bag_id(bag)
- return bag.id
-end
-
-local bags = res.bags:filter(filter_bag):key_map(get_bag_command):map(get_bag_id)
-
-local support_npcs = {
- {name = "Orechiniel", zone = 230, menu = 650, buff = 240},
- {name = "Greubaque", zone = 231, menu = 628, buff = 237},
- {name = "Ulycille", zone = 231, menu = 623, buff = 236},
- {name = "Azima", zone = 234, menu = 122, buff = 242},
- {name = "Fatimah", zone = 235, menu = 302, buff = 238},
- {name = "Wise Owl", zone = 237, menu = 103, buff = 237},
- {name = "Kipo-Opo", zone = 238, menu = 10015, buff = 243},
- {name = "Lih Pituu", zone = 241, menu = 10018, buff = 241},
- {name = "Terude-Harude", zone = 241, menu = 10013, buff = 239},
- {name = "Fleuricette", zone = 256, menu = 1201, buff = 512},
- {name = "Quiri-Aliri", zone = 257, menu = 1201, buff = 512},
-}
-
-local exceptions = {
- ['Geo Crystal'] = 6509,
- ['Fire Card'] = 9764,
- ['Ice Card'] = 9765,
- ['Wind Card'] = 9766,
- ['Earth Card'] = 9767,
- ['Lightning Card'] = 9768,
- ['Water Card'] = 9769,
- ['Light Card'] = 9770,
- ['Dark Card'] = 9771,
-}
-
-local clusters = {
- ['Fire Crystal'] = 'Fire Cluster',
- ['Ice Crystal'] = 'Ice Cluster',
- ['Wind Crystal'] = 'Wind Cluster',
- ['Earth Crystal'] = 'Earth Cluster',
- ['Lightng. Crystal'] = 'Lightning Cluster',
- ['Water Crystal'] = 'Water Cluster',
- ['Light Crystal'] = 'Light Cluster',
- ['Dark Crystal'] = 'Dark Cluster',
-}
-
-local hqcrystal = {
- ['Fire Crystal'] = 'Inferno Crystal',
- ['Ice Crystal'] = 'Glacier Crystal',
- ['Wind Crystal'] = 'Cyclone Crystal',
- ['Earth Crystal'] = 'Terra Crystal',
- ['Lightng. Crystal'] = 'Plasma Crystal',
- ['Water Crystal'] = 'Torrent Crystal',
- ['Light Crystal'] = 'Aurora Crystal',
- ['Dark Crystal'] = 'Twilight Crystal',
-}
-
-local help_commands = [[
-craft - Command List:
-1. help - Displays this message.
-2. repeat - Repeats synthesis (default 1) using the
- lastsynth command.
-* repeat - Repeats 1 synthesis
-* repeat 13 - Repeats 13 synthesis
-3. make - Issue a synthesis command using a recipe name
-* make "Sheep Leather" - Makes 1 Sheep Leather
-* make "Sheep Leather" 5 - Makes 5 Sheep Leather
-4. put - Moves all copies of an item into available bags.
-* put "Dragon Mask" - Moves all Dragon Masks in inventory
- to any available bags.
-* put "Dragon Mask" satchel - Moves all Dragon Masks in
- inventory to Mog Satchel.
-* put "Dragon Mask" safe2 - Moves all Dragon Masks to Mog
- Safe 2 (if available).
-5. delay - Sets the delay between crafting attempts
- (default 24, minimum 17)
-* delay 30 - Sets the delay between crafting to 30
- seconds.]]
-
-local help_commands_2 = [[
-6. food - Sets a food item that will automatically
- be consumed while crafting.
-* food - Sets the auto food to None.
-* food "Kitron Macaron" - Sets the auto food
- to Kitron Macaron.
-7. pause - Pauses the addon.
-8. resume - Resumes the addon.
-9. clear - Clears all items in the queue.
-10. jiggle - Set a key that will be pressed between every
- queue item (default disabled.)
-* jiggle - Disables the jiggle feature.
-* jiggle escape - Sets the jiggle key to escape.
-11. support - Toggles auto support/ionis (default off)
-* Must be near an NPC that offers Ionis or advanced
- imagery support to work.
-* Determines whether items will be sold instantly or slowly.
-12. status - Display some information about the
- addon's current state.
-13. find - Search for a recipe fromt the recipes list using
- a string.
-* find "Pizza" - Finds and displays all recipes containing
- the string "Pizza".
-* find "Pizza" details - Finds and displays all recipes
- containing the string "Pizza" (ingredients/crystal are
- also displayed.)
-14. display - Toggles whether outgoing crafting
- packets are displayed in the chat log.
-15. hqcrystal - Toggle whether to use HQ Crystal
-]]
-
-local help_notes = [[
-Notes:
- Make commands will automatically pull items from
- any available bags if they are not present in your
- inventory. This includes all recipe ingredients
- and the crystal. If a crystal cannot be found,
- it will search for a cluster from your inventory
- and available bags and use the cluster. These
- features are not supported with the repeat command.
-
- The available recipes are stored in recipes.lua.
- The order in which ingredients are entered matter.
- To add new recipes, enable the display (//craft
- display) and manually synthesis an item. The
- packet will be printed to your chat log. Create
- an entry similar to the recipes that are already
- provided. Only add the actual ingredients and
- crystal. Then save recipes.lua and reload the addon.
-
- Ingredients and food are case sensitive and use
- the short english name. These are the ones
- displayed on FFXIAH.
-]]
-
-local function validate(npcs)
- zone = windower.ffxi.get_info()['zone']
- local valid = false
- for _, npc in pairs(npcs) do
- if zone == npc.zone then
- valid = true
- local mob = windower.ffxi.get_mob_by_name(npc.name)
- if mob then
- if (math.sqrt(mob.distance) < 6) then
- return mob, npc
- end
- end
- end
- end
- if valid then
- warning("Too far from away from NPC")
- end
-end
-
-local function get_support(id, data)
- if (id == 0x34) and conditions['support'] then
- local mob, npc = validate(support_npcs)
- local p = packets.new('outgoing', 0x5b, {
- ["Target"] = mob.id,
- ["Option Index"] = 1,
- ["Target Index"] = mob.index,
- ["Automated Message"] = false,
- ["Zone"] = zone,
- ["Menu ID"] = npc.menu,
- })
- packets.inject(p)
- conditions['support'] = false
- return true
- end
-end
-
-local function check_bag(bag, id)
- if not inventory['enabled_%s':format(bag)] then
- return false
- end
- local contents = inventory[bag]
- for index = 1, inventory['max_%s':format(bag)] do
- if contents[index].id == id then
- conditions['sort'] = true
- conditions['move'] = true
- windower.ffxi.get_item(bags[bag], index, contents[index].count)
- return true
- end
- end
- return false
-end
-
-local function check_bags(id)
- if inventory['count_inventory'] == inventory['max_inventory'] then
- return false
- end
- for bag, bag_id in pairs(bags) do
- if check_bag(bag, id) then
- return true
- end
- end
- return false
-end
-
-local function block_sort(id, data)
- if (id == 0x3a) and conditions['sort'] then
- return true
- end
-end
-
-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)
- else
- inventory = windower.ffxi.get_items()
- end
-end
-
-local function poke_npc()
- local mob, npc = validate(support_npcs)
- if npc then
- local player = windower.ffxi.get_player()
- if S(player.buffs):contains(npc.buff) then
- return
- end
- conditions['support'] = true
- local p = packets.new('outgoing', 0x01a, {
- ["Target"] = mob.id,
- ["Target Index"] = mob.index,
- ["Category"] = 0,
- ["Param"] = 0,
- ["_unknown1"] = 0,
- })
- packets.inject(p)
- return busy_wait('support', 10, "getting crafting buff")
- end
-end
-
-local function unblock_sort(id, data)
- if id == 0x1d then
- conditions['move'] = false
- end
-end
-
-local function unblock_item(id, data)
- if (id == 0x20) then
- p = packets.parse('incoming', data)
- if p['Item'] == conditions['item'] then
- conditions['item'] = false
- end
- end
-end
-
-local function commence_jigglin()
- windower.send_command('setkey %s down':format(jiggle))
- coroutine.sleep(.25)
- windower.send_command('setkey %s up':format(jiggle))
-end
-
-local function consume_item(item)
- windower.chat.input('/item \"%s\" <me>':format(item))
- coroutine.sleep(3.5)
- inventory = windower.ffxi.get_items()
-end
-
-local function fetch_ingredient(ingredient)
-
- local id, name
- if exceptions[ingredient] then
- id = exceptions[ingredient]
- else
- item = res.items:name(ingredient)
- id, name = next(item, nil)
- end
- if id then
- local contents = inventory['inventory']
- for index = 1, inventory['max_inventory'] do
- if appropriated[index] == nil then
- appropriated[index] = 0
- end
- if (contents[index].id == id) and
- (contents[index].count > appropriated[index]) then
- appropriated[index] = appropriated[index] + 1
- return id, index
- end
- end
- if check_bags(id) then
- local status = busy_wait('move', 10, 'moving %s':format(ingredient))
- if status then
- return status
- else
- return fetch_ingredient(ingredient)
- end
- end
- if clusters[ingredient] then
- local cluster = clusters[ingredient]
- local cluster_id, cluster_index = fetch_ingredient(cluster)
- if cluster_index then
- conditions['sort'] = true
- conditions['item'] = id
- local start = os.time()
- windower.chat.input('/item \"%s\" <me>':format(cluster))
- local status = busy_wait('item', 10, 'using %s':format(cluster))
- if status then
- error(status)
- end
- coroutine.sleep(4 - (os.time() - start))
- inventory = windower.ffxi.get_items()
- return fetch_ingredient(ingredient)
- end
- end
- return "Unable to locate %s":format(ingredient)
- else
- return "Unknown item %s":format(ingredient)
- end
-end
-
-local function consume_food()
- local player = windower.ffxi.get_player()
- if S(player.buffs):contains(251) then
- return
- end
- inventory = windower.ffxi.get_items()
- local id, index = fetch_ingredient(food)
- if index then
- windower.chat.input('/item \"%s\" <me>':format(food))
- coroutine.sleep(3.5)
- else
- warning("Unable to consume %s":format(food))
- end
-end
-
-local function fetch_recipe(item)
- local item = item:lower()
- for name, recipe in pairs(recipes) do
- if item == name:lower() then
- return recipe
- end
- end
-end
-
-local function hash(crystal, item, count)
- local c = ((crystal % 6506) % 4238) % 4096
- local m = (c + 1) * 6 + 77
- local b = (c + 1) * 42 + 31
- local m2 = (8 * c + 26) + (item - 1) * (c + 35)
- return (m * item + b + m2 * (count - 1)) % 127
-end
-
-local function build_recipe(item)
- if windower.ffxi.get_player().status ~= 0 then
- return "You can't craft at the moment"
- end
-
- local recipe = fetch_recipe(item)
-
- if recipe then
- inventory = windower.ffxi.get_items()
- appropriated = {}
- local p = packets.new('outgoing', 0x096)
- local crystal = recipe['crystal']
- if hqsynth then
- crystal = hqcrystal[crystal]
- end
- local id, index = fetch_ingredient(crystal)
- if not index then return id end
- p['Crystal'] = id
- p['Crystal Index'] = index
- p['Ingredient count'] = #recipe['ingredients']
- for i, ingredient in pairs(recipe['ingredients']) do
- id, index = fetch_ingredient(ingredient)
- if not index then return id end
- p["Ingredient %i":format(i)] = id
- p["Ingredient Index %i":format(i)] = index
- end
- p['_unknown1'] = hash(p['Crystal'], p['Ingredient 1'], p['Ingredient count'])
- return p
- else
- return "No recipe for %s":format(item)
- end
-end
-
-local function issue_synthesis(item)
- local p = build_recipe(item)
- if type(p) == 'string' then
- skip_delay = true
- conditions['sort'] = false
- return "%s - %s":format(item, p)
- else
- packets.inject(p)
- conditions['sort'] = false
- end
-end
-
-local function repeat_synthesis()
- windower.chat.input('/lastsynth')
-end
-
-local function put_items(bag, id)
- local src = inventory['inventory']
- local dst = inventory[bag]
- local empty = {}
- for index = 1, inventory['max_%s':format(bag)] do
- if dst[index].count == 0 then
- empty[index] = true
- end
- end
- local idx, status = next(empty, nil)
- for index = 1, inventory['max_inventory'] do
- if (src[index].id == id) and idx then
- windower.ffxi.put_item(bags[bag], index, src[index].count)
- dst[idx].id = id
- dst[idx].count = src[index].count
- src[index].id = 0
- src[index].count = 0
- idx, status = next(empty, idx)
- delta = true
- end
- end
-end
-
-local function put(args)
- conditions['sort'] = true
- delta = false
- inventory = windower.ffxi.get_items()
- if args['bag'] then
- local bag = args['bag']
- if not inventory['enabled_%s':format(bag)] then
- block = false
- return "bag %s disabled":format(bag)
- end
- put_items(bag, args['id'])
- else
- for bag, bag_id in pairs(bags) do
- if inventory['enabled_%s':format(bag)] then
- put_items(bag, args['id'])
- end
- end
- end
- if delta then
- delta = false
- busy_wait('move', 10, 'moving %s':format(args['name']))
- end
- conditions['sort'] = false
- coroutine.sleep(3.5)
- skip_delay = true
-end
-
-local function check_queue()
- if not queue:empty() then
- if not paused then
- if jiggle then
- commence_jigglin()
- end
- if support then
- poke_npc()
- end
- if food then
- consume_food()
- end
- local fn, arg = unpack(queue:pop())
- local msg = fn(arg)
- if msg then
- error(msg)
- end
- if skip_delay then
- coroutine.schedule(check_queue, 0)
- skip_delay = false
- else
- coroutine.schedule(check_queue, delay)
- end
- end
- else
- busy = false
- end
-end
-
-local function process_queue()
- if not busy then
- busy = true
- coroutine.schedule(check_queue, 0)
- end
-end
-
-local function handle_help()
- windower.add_to_chat(100, help_commands)
- windower.add_to_chat(100, help_commands_2)
- windower.add_to_chat(100, help_notes)
-end
-
-local function handle_status()
- notice("delay", delay)
- notice("paused", paused)
- notice("display", display)
- notice("auto food", food)
- notice("auto support", support)
- notice("jiggle", jiggle)
- notice("queue size", queue:length())
- notice("hq crystal", hqsynth)
-end
-
-local function handle_delay(seconds)
- local n = tonumber(seconds)
- if n == nil then
- return "Invalid delay %s":format(seconds)
- else
- n = math.max(17, n)
- notice("Setting delay to %d":format(n))
- delay = n
- end
-end
-
-local function handle_clear()
- notice("Clearing queue")
- queue = Q{}
-end
-
-local function handle_pause()
- notice("Pausing")
- paused = true
-end
-
-local function handle_resume()
- notice("Resuming")
- if paused then
- paused = false
- busy = false
- process_queue()
- end
-end
-
-local function handle_jiggle(key)
- if key then
- notice("Setting jiggle to %s key":format(key))
- jiggle = key
- else
- notice("Removing jiggle")
- jiggle = false
- end
-end
-
-local function handle_repeat(count)
- local count = count or 1
- local n = tonumber(count)
- if n == nil then
- return "Invalid count %s":format(count)
- end
- notice("Adding %d repeat commands to the queue":format(count))
- for i = 1, count do
- local item = {repeat_synthesis, nil}
- queue:push(item)
- end
- process_queue()
-end
-
-local function handle_make(item, count)
- local count = count or 1
- local n = tonumber(count)
- if n == nil then
- return "Invalid count %s":format(count)
- end
- local recipe = fetch_recipe(item)
- if not recipe then
- return "No recipe for %s":format(item)
- end
- notice("Adding %d make %s commands to the queue":format(count, item))
- for i = 1, count do
- local item = {issue_synthesis, item}
- queue:push(item)
- end
- process_queue()
-end
-
-local function handle_food(item)
- if not item then
- notice("Setting auto food to None")
- food = false
- else
- local search = res.items:name(item)
- local id, name = next(search, nil)
- if id then
- notice("Setting auto food to %s":format(name.en))
- food = name.en
- else
- return "Invalid food %s":format(item)
- end
- end
-end
-
-local function handle_put(ingredient, bag)
- if bag then
- bag = bag:lower()
- if not bags[bag] then
- return "Unknown bag %s":format(bag)
- end
- end
- local search = res.items:name(ingredient)
- local id, name = next(search, nil)
- if id then
- local msg = nil
- local args = {
- ['id'] = id,
- ['bag'] = bag,
- ['name'] = name.english,
- }
- local item = {put, args}
- if bag then
- msg = "%s %s":format(ingredient, bag)
- else
- msg = ingredient
- end
- notice("Adding a put %s command to the queue":format(msg))
- queue:push(item)
- process_queue()
- else
- return "Unknown item %s":format(ingredient)
- end
-end
-
-local function display_crafting_packet(id, data)
- if id == 0x096 and display then
- local p = packets.parse('outgoing', data)
- log(p)
- end
-end
-
-local function handle_display()
- if display then
- notice("Disabling display")
- display = false
- else
- notice("Enabling display")
- display = true
- end
-end
-
-local function handle_support()
- if support then
- notice("Disabling support")
- support = false
- else
- notice("Enabling support")
- support = true
- end
-end
-
-local function handle_find(query, details)
- local query = query:lower()
- notice("Searching for recipes containing %s":format(query))
- for name, recipe in pairs(recipes) do
- if string.find(name:lower(), query) then
- notice("Found recipe - \"%s\"":format(name))
- if details then
- notice(" %s":format(recipe['crystal']))
- for _, ingredient in pairs(recipe['ingredients']) do
- notice(" %s":format(ingredient))
- end
- end
- end
- end
-end
-
-local function handle_hqsynth()
- if hqsynth then
- notice("Disabling HQ Crystal")
- hqsynth = false
- else
- notice("Enabling HQ Crystal")
- hqsynth = true
- end
-end
-
-
-handlers['clear'] = handle_clear
-handlers['repeat'] = handle_repeat
-handlers['r'] = handle_repeat
-handlers['delay'] = handle_delay
-handlers['pause'] = handle_pause
-handlers['resume'] = handle_resume
-handlers['make'] = handle_make
-handlers['m'] = handle_make
-handlers['display'] = handle_display
-handlers['put'] = handle_put
-handlers['food'] = handle_food
-handlers['status'] = handle_status
-handlers['help'] = handle_help
-handlers['jiggle'] = handle_jiggle
-handlers['support'] = handle_support
-handlers['find'] = handle_find
-handlers['hqcrystal'] = handle_hqsynth
-
-local function handle_command(cmd, ...)
- local cmd = cmd or 'help'
- if handlers[cmd] then
- local msg = handlers[cmd](unpack({...}))
- if msg then
- error(msg)
- end
- else
- error("Unknown command %s":format(cmd))
- end
-end
-
--- This is here so if a player does a legitimate synth the result is not displayed twice, since results are only hidden on injected synthesis.
-windower.register_event('outgoing chunk', function(id, original, modified, injected, blocked)
- if id == 0x096 and injected then
- injected_synth = true
- end
-end)
-
-windower.register_event('incoming chunk', function(id, original, modified, injected, blocked)
- if id == 0x06F and injected_synth then
- local p = packets.parse('incoming',original)
- if p['Result'] == 0 or p['Result'] == 2 then
- local item = res.items[p['Item']].english
- windower.add_to_chat(121, 'You synthesized: \30\02%s\30\01.':format(item))
- injected_synth = false
- end
- if p['Result'] == 1 or p['Result'] == 5 then
- windower.add_to_chat(121,'Your synthesis has failed and your crystal is lost.')
- for i=1, 8 do
- if p['Lost Item '..i] ~= 0 then
- windower.add_to_chat(121, 'You lost: \30\02%s\30\01.':format(res.items[p['Lost Item '..i]].english))
- end
- end
- injected_synth = false
- end
- end
-end)
-
-windower.register_event('addon command', handle_command)
-windower.register_event('outgoing chunk', display_crafting_packet)
-windower.register_event('outgoing chunk', block_sort)
-windower.register_event('incoming chunk', unblock_sort)
-windower.register_event('incoming chunk', unblock_item)
-windower.register_event('incoming chunk', get_support)